62 votes

Comment router vers un Module en tant qu'enfant d'un Module - Angular 2 RC 5

Je suis en train de mettre à jour une application sur laquelle je travaille vers la dernière version candidate d'Angular 2. Dans le cadre de ce travail, j'essaie d'utiliser la spécification NgModule et de migrer toutes les parties de mon application vers des modules. Pour l'essentiel, cela s'est très bien passé à l'exception d'un problème de routage.

"@angular/common": "2.0.0-rc.5",
"@angular/compiler": "2.0.0-rc.5",
"@angular/core": "2.0.0-rc.5",
"@angular/forms": "0.3.0",
"@angular/http": "2.0.0-rc.5",
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"@angular/router": "3.0.0-rc.1",

Mon application est construite comme une composition de modules, plusieurs modules étant collés ensemble en tant qu'enfants d'un module parent. Par exemple, j'ai un module d'administration qui se compose d'un module de notifications, d'un module d'utilisateurs et d'un module de téléphonie (par exemple). Les routes vers ces modules devraient ressembler à...

/admin/notifications/my-notifications
/admin/users/new-user
/admin/telephony/whatever

Dans les versions antérieures du routeur, il était facile d'y parvenir en utilisant les "enfants"

export const AdminRoutes: RouterConfig = [
   {
      path: "Admin",
      component: AdminComponent,
      Children: [
         ...UserRoutes,
         ...TelephonyRoutes,
         ...NotificationRoutes
      ]
   }
]

Dans un autre fichier, dans le cadre des sous-modules, je définirais également les itinéraires des modules individuels, à savoir

export const UserRoutes: RouterConfig = [
    {
       path: "users",
       component: userComponent,
       children: [
           {path: "new-user", component: newUserComponent}
       ]
    }

]

Tout cela a très bien fonctionné. Lors de la mise à jour vers les modules, j'ai déplacé tous les éléments dans leurs propres fichiers de routage individuels, de sorte que ces deux fichiers ressemblent maintenant à ceci

const AdminRoutes: Routes = [
    {path: "admin", component: AdminComponent}
] 

export const adminRouting = RouterModule.forChild(AdminRoutes)

et

const UserRoutes: Routes = [
       path: "users",
       component: userComponent,
       children: [
           {path: "new-user", component: newUserComponent}
       ]
] 

export const userRouting = RouterModule.forChild(UserRoutes)

Avec tout cela en place, j'ai un UsersModule qui importe le userRouting, puis un AdminModule qui importe les adminRoutes et le UsersModule. Je pensais que puisque UsersModule est un enfant de AdminModule, le routage fonctionnerait comme avant. Malheureusement, ce n'est pas le cas et je me retrouve avec une route users qui est juste

/users/new-user 

au lieu de

/admin/users/new-user

De plus, à cause de cela, le composant nouvel utilisateur n'est pas chargé dans la sortie du routeur de mon composant d'administration, ce qui perturbe le style et la navigation de mon application.

Je n'arrive pas à trouver comment référencer les routes de mon UserModule en tant qu'enfants de mon AdminModule. J'ai essayé de le faire à l'ancienne et j'obtiens des erreurs parce que les routes sont dans deux modules. Évidemment, comme il s'agit d'une nouvelle version, la documentation sur certains de ces cas est un peu limitée.

Toute aide que vous pourriez apporter serait grandement appréciée !

53voto

Marcus Riemer Points 2187

Après avoir passé une bonne partie du week-end à bricoler, j'ai réussi à faire fonctionner le système de mon côté. Ce qui a fonctionné pour moi à la fin, c'est de faire ce qui suit :

  • Exporter tout Routes pour chaque module que vous souhaitez acheminer. N'importez aucun des modules RouterModule.forChild() dans les modules enfants.
  • Exportation tous qui est visible à partir des définitions d'itinéraires des enfants dans la définition du module des enfants.
  • Importation (c'est-à-dire l'importation de Typescript import ) toutes les routes enfants comme d'habitude et utiliser le mot-clé ... pour les incorporer dans le bon chemin. Je n'ai pas réussi à le faire fonctionner avec le module enfant définissant le chemin, mais l'avoir sur le parent fonctionne bien (et est compatible avec le chargement paresseux).

Dans mon cas, j'avais trois niveaux dans une hiérarchie comme celle-ci :

  • Racine ( / )
    • Éditeur ( editor/:projectId )
      • Requête ( query/:queryId )
      • Page ( page/:pageId )
    • Avant ( about )

Les définitions suivantes me conviennent pour le /editor/:projectId/query/:queryId chemin :

// app.routes.ts
import {editorRoutes}                   from './editor/editor.routes'

// Relevant excerpt how to load those routes, notice that the "editor/:projectId"
// part is defined on the parent
{
    path: '',
    children: [
        {
            path: 'editor/:projectId',
            children: [...editorRoutes]
            //loadChildren: '/app/editor/editor.module'
        },
    ]
}

Les itinéraires de l'éditeur se présentent comme suit :

// app/editor/editor.routes.ts
import {queryEditorRoutes}              from './query/query-editor.routes'
import {pageEditorRoutes}               from './page/page-editor.routes'

{
    path: "", // Path is defined in parent
    component : EditorComponent,
    children : [
        {
            path: 'query',
            children: [...queryEditorRoutes]
            //loadChildren: '/app/editor/query/query-editor.module'
        },
        {
            path: 'page',
            children: [...pageEditorRoutes]
            //loadChildren: '/app/editor/page/page-editor.module'
        }
    ]
}

La partie finale de l'éditeur de requêtes ressemble à ceci :

// app/editor/query/query-editor.routes.ts
{
    path: "",
    component : QueryEditorHostComponent,
    children : [
        { path: 'create', component : QueryCreateComponent },
        { path: ':queryId', component : QueryEditorComponent }
    ]
}

Toutefois, pour que cela fonctionne, il faut que les Editor doit importer et exporter le QueryEditor et le QueryEditor doit exporter QueryCreateComponent y QueryEditorComponent car ils sont visibles lors de l'importation. Si vous ne le faites pas, vous obtiendrez des erreurs du type Component XYZ is defined in multiple modules .

Notez que le chargement paresseux fonctionne également très bien avec cette configuration, dans ce cas les routes enfants ne doivent pas être importées bien sûr.

34voto

Jklf Points 392

J'ai eu le même problème.

La réponse à cette question est assez bonne : utiliser loadChildren :

          {
             path: 'mypath',
             loadChildren : () => myModule
          }

https://github.com/angular/angular/issues/10958

3voto

Leonid Gorshkov Points 11

Je pense que la 2.0.0 rc5 n'est pas intéressée pour l'instant. Mais c'est travaillé dans Angular 4, peut être en avance aussi.

@NgModule({
    imports: [
        RouterModule.forRoot([
                {path: "", redirectTo: "test-sample", pathMatch: "full"},
                {
                    path: "test-sample",
                    loadChildren: () => TestSampleModule
                }
        ])
    ],
    exports: [RouterModule],
    declarations: [] 
}) 
export class AppRoutingModule{}

@NgModule({
    imports: [
        RouterModule.forChild([{
                    path: "",
                    component: TestSampleComponent,
                    children: [
                        {path: "", redirectTo: "home", pathMatch: "full"},
                        {
                            path: "home",
                            loadChildren: () => HomeModule
                        },
                        {
                            path: "about",
                            loadChildren: () => AboutModule
                        }
                    ]
                }
        ])
    ],
    exports: [RouterModule],
    declarations: []
})
export class TestSampleRoutingModule {}

@NgModule({
    imports: [RouterModule.forChild([{
                    path: "",
                    component: AboutComponent
                }
    ])],
    exports: [RouterModule]
})
export class AboutRoutingModule {}

Tenir compte de loadChildren: () => {...} . Il ne s'agit pas d'un chargement paresseux.

Voir les détails feat : Prise en charge de la hiérarchie NgModules sans Lazy Loading

1voto

John Ackerman Points 561

J'ai également trouvé un moyen de résoudre ce problème. En fait, je définis mes routes comme je le faisais auparavant, mais cette fois au niveau de l'enfant le plus élevé. Par exemple ma route admin :

const AdminRoutes: Routes = [
   {
      path: 'admin',
      component: AdminComponent,
      children: [
          ...setupRoutes
      ]
   }
]

export const adminRouting = RouterModule.forChild(AdminRoutes)

Mon fichier d'itinéraires de configuration est importé d'une sous-région, qui définit ses propres itinéraires, y compris d'autres enfants. Le problème est que ce fichier exporte l'objet "Routes" et non le résultat RouterModule.forChild.

Après cela, j'ai supprimé les routes enfant et sous-enfant des définitions des sous-modules. J'ai ensuite dû exporter tous les composants utilisés dans les routes, à partir de chacun des sous-modules, comme Marcus l'a mentionné plus haut. Une fois que j'ai fait cela, les routes ont commencé à fonctionner comme je le voulais.

Je ne pense pas que cette solution me plaise vraiment car mon module parent en sait trop sur les itinéraires du module enfant. Mais au moins, c'est un moyen facile de contourner le problème pour RC5, et il n'y a pas de fuite de tous mes composants partout. Je vais aller de l'avant et marquer la réponse de Marcus comme étant la réponse puisqu'il m'a mis sur la bonne voie.

0voto

westor Points 62

Lorsque vous utilisez ngModules et RC5, la configuration du routage de votre module parent n'a pas besoin de connaître le routage des modules enfants. Vous n'avez qu'à définir les routes de votre module parent ici. De plus, vous devez importer le module enfant dans votre module parent. Dans le module enfant, vous devez définir vos itinéraires de cette manière :

export const childRoutes: Routes = [
  {
    path: 'someChild',
      component: SomeChildComponent,
      children: [
        { path: '', component: SomeChildSubComponent1 },
        { path: 'comp1', component: SomeChildSubComponent1 },
        { path: 'comp2', component: SomeChildSubComponent2 }
      ]
  }
];

Cela vous permettra d'avoir une url comme /someParent/someChild/comp1 - et les composants sont affichés dans leur router-outlet correspondant. Remarque : vous DEVEZ déclarer un composant pour le chemin vide. Sinon, vous ne pourrez pas naviguer vers vos enfants.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X