Junior Dussouillez
Junior Dussouillez

Reputation: 2397

Router-outlet is not updating after Routerlink navigation

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 :

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.

Angular_router_bug Angular_router_bug_2

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 :

  1. Click on the link "Block #1"
  2. Refresh the Stackblitz output window
  3. Click on "Block #0" or "Details" : the route is changed but the message is still "details block1"
  4. Click on "Info"
  5. Repeat step 1. -> now the problem is fixed.

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

Answers (3)

Abhinav Atul
Abhinav Atul

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

Dorian
Dorian

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

mast3rd3mon
mast3rd3mon

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

Related Questions