Reputation: 2397
I'm creating a simple Angular app with a navigation menu. Each menu item has a Routerlink
to navigate between the pages. Here's the pages :
#/home
)#/customer/info
)#/customer/details
)#/customer/details/b0
)#/customer/details/b1
)Relevant code :
app.module.ts
@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(
[
{
path: "",
redirectTo: "home",
pathMatch: "full"
},
{
path: "home",
component: HomeComponent
},
{
path: "customer",
component: CustomerComponent,
children: [
{
path: "",
redirectTo: "info",
pathMatch: "full"
},
{
path: "info",
component: CustomerInfoComponent,
},
{
path: "details",
component: CustomerDetailsComponent,
children: [
{
path: "",
redirectTo: "b0",
pathMatch: "full"
},
{
path: "b0",
component: CustomerDetailsBlock0Component
},
{
path: "b1",
component: CustomerDetailsBlock1Component
},
]
}
]
}
],
{useHash: true}
)
],
declarations: [ AppComponent, CustomerComponent, MenuComponent, HomeComponent, CustomerInfoComponent, CustomerDetailsComponent, CustomerDetailsBlock0Component, CustomerDetailsBlock1Component ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
customer-component.html
<p>This is customer #{{id}}</p>
<app-menu>
<router-outlet></router-outlet>
</app-menu>
customer-details-component.html
<p>This is customer details</p>
<router-outlet></router-outlet>
customer-details-block0-component.html
<p>details block0</p>
customer-details-block1-component.html
<p>details block1</p>
menu-component.html
<div>
<ul>
<li>
<a routerLink="">Home</a>
</li>
<li>
<a routerLink="../customer">Customer</a>
<ul>
<li>
<a routerLink="../customer/info">Info</a>
</li>
<li>
<a routerLink="../customer/details">Details</a>
<ul>
<li>
<a routerLink="../customer/details/b0">Block #0</a>
</li>
<li>
<a routerLink="../customer/details/b1">Block #1</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>------------- Content inside menu router-outlet -------------</p>
<router-outlet></router-outlet>
<p>--------------------------------------------------------------------</p>
</div>
The navigation works fine : when I click on a link, the activated route changed, the router-outlet
are updated and the expected components are displayed.
The problem comes when I refresh the page when the route is #/customer/details/b1
(or if I click directly on it, without clicking on the parent menu item) : The components are the good ones, but my menu is broken. If I click on the link to go the #/customer/details/b0
the route is changed but the router-outlet are not updated, the b1
component is still displayed and b0
isn't.
This is fixed when I click on another menu item where the URL does not starts with "customer/details", for example if I click on "Info" then the issue is gone.
I guess it's a problem about the component customer-details
being the same instance and so Angular reuse it. But then why the child components are not changed ?
I managed to "fix" this behavior by returning false everytime the router shouldReuseRoute function is called :
// menu-component.ts
constructor(private router: Router) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
}
But I do not want the destroy/create all my components every time. Are there any solutions to this ?
Here's the Stackblitz demo. To reproduce the bug :
EDIT: I still have the issue with Angular v6.1.3 (I updated the Stackblitz demo). I tried all the solutions provided by @mast3rd3mon but nothing seems to fix it.
Upvotes: 3
Views: 6654
Reputation: 629
Merge CustomerDetailsBlock0Component
, CustomerDetailsBlock1Component
into CustomerDetailsBlockComponent
with route param ':blockId'
CustomerDetailsBlockComponent{
blockId: number
constructor(private router Router){
this.router.events.subscribe(event=>{
if (event instanceof ActivationEnd && event.snapshot) {
let blockId = +event.snapshot.paramMap.get('blockId')
if (blockId) {
this.blockId = blockId
//update other angular bindings
}
}
})
}
}
Upvotes: 0
Reputation: 761
The issue comes from the MenuComponent
. You have to insert <ng-content></ng-content>
instead of <router-outlet></router-outlet>
because the component behind <router-outler></router-outlet>
is init in the component which call the MenuComponent
(CustomerComponent
in this example).
So the code in menu.component.html
should be :
<p>------------- Content inside menu router-outlet -------------</p>
<ng-content></ng-content>
<p>--------------------------------------------------------------------</p>
Upvotes: 2
Reputation: 8835
After looking at the demo you made, you need to remove the ..
part of the router links. ../customer
becomes /customer
, ../customer/info
becomes /customer/info
etc.
It might have just been the demo but make sure that the app.component.html file looks like <router-outlet></router-outlet>
not <router-outlet>
as the tag needs to have a closing tag.
Upvotes: 3