Reputation: 572
I want to be able to use the same router-outlet for some routes.
Routing setup (simplified):
export const routes: Routes = [
{
path: 'app', component: AppComponent,
children: [
path: 'category/:id', component: CategoryComponent,
children: [
{ path: 'post/:id', component: PostComponent }
]
]
}
];
For example we have this path:
/app/category/1/post/1
That breaks into
/app - AppComponent
|_ /catory/1 - CategoryComponent
|_/post/1 - PostComponent
The AppComponent
has a <router-outlet>
which renders CategoryComponent
,
but should also render the PostComponent
when that route is active.
Common answers for this type of question:
Move the child routes and add them in the app-route children array
No. This isn't the right way. We still want our hierarchy of routes. CategoryComponent
may know something which PostComponent
doesn't - Such as Breadcrumb
naming
So we still want our CategoryComponent to load. (Even if it's view isn't renders)
Use a <router-outlet>
inside of CategoryComponent
No. The CategoryComponent
should not be in charge of it's own <router-outlet>
.
The PostComponent
should be rendered in place of the CategoryComponent
, and add CSS to place it like that should be illegal.
How can I acheive this behaviour?
Do i need to write my own router-outlet?
Will this be solved in Angular4?
Any tips are welcome! Thanks
Upvotes: 10
Views: 5579
Reputation: 4469
The answer here will work.
Depending on how you're building breadcrumbs, you may have to have several nested levels of children: []
with path: ''
.
path
properties, which if there are ''
, will just walk up to use the parents path
property.data: {breadcrumb: 'crumb'}
or data: {title: 'crumb'}
or whatever it is looking for, it will build that into the breadcrumb chain.Thus, you can make breadcrumbs as long as needed, and have paths be as long as needed, but as long as you don't nest components, you'll get what you're after.
export const routes: Routes = [
{
path: 'app',
component: AppComponent,
data: {
title: 'App',
},
children: [
{
path: 'category/:id', // appends to path `app`
children: [
{
path: '',
data: {
title: 'Category', // appends to breadcrumb `App`
},
children: [
{
path: '',
component: CategoryComponent, // renders in `AppComponent`
data: {
title: '', // Specify a blank on so that we don't duplicate the parent one
},
},
{
path: 'post/:id', // appends to path `app/category/:id`
component: PostComponent, // renders in `AppComponent`
data: {
title: 'Post', // appends to breadcrumb `App / Category`
},
},
],
},
],
},
],
},
];
Upvotes: 2
Reputation: 1940
Since we're meanwhile at Angular 7 and there seems to be no documentation for this, I guess that there is no simple out-of-the box solution for the problem.
I had a very similar problem: The child route of a lazy loaded module should be rendered inside the app component's outlet and not inside an outlet of the lazy loaded module. I'm working with lazy loaded modules but you probably can transform this idea to your use case. I was able to solve the issue by defining the according route on the expected outlet level, meaning inside the AppRoutes (I think there is no other way):
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path: 'category/:cid',
loadChildren: './category/category.module#CategoryModule',
},
{
path: 'category/:cid/post/:pid',
loadChildren: './category/post/post.module#PostModule'
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
This way I can at least guarantee the folder structure and URL hierarchy remain the way I want them to be. In order to solve the state management problem you mentioned, I would deserialize data about categories inside the PostComponent or PostRoute. However, this would introduce some maybe unwanted redundancy.
To me this is far from ideal, because I'm not able to encapsulate things inside lazy loaded modules the way I want. But: it's working.
Upvotes: 1
Reputation: 195
If I get it right, you can try to solve the problem using something like "wrappers". This way (I have not tested this code, but it should work; read the inline comments):
export const routes: Routes = [
{
path: 'app',
component: AppComponent,
children: [
{
path: 'category/:id', // app/category/:id/
children: [
{
path: '', // app/category/:id/ => By default, empty paths serve as if they were the parent path.
component: CategoryComponent,
children: [ // These children will be inside the <router-outlet> of the CategoryComponent.
{
path: 'subcategory1', // app/category/:id/subcategory1
component: PostComponent,
},
{
path: 'subcategory2', // app/category/:id/subcategory2
component: PostComponent,
}
]
},
{ // The PostComponent will use AppComponent as its parent; will be loading inside the <router-outlet> of AppComponent.
path: 'post/:id', // app/category/:id/post/:id
component: PostComponent
}
]
}
],
},
];
Upvotes: 4