Search code examples
angularroutesurl-routing

Angular: child route is not updated correctly


I have a UserComponent (route user/:userId) with a button. When the button is clicked, the route changes to user/123/hobby/456 which triggers a HobbyComponent. This component has a pagination with "next" and "previous" buttons. When one of the buttons is clicked, I need to do the following:

  1. Change the route to the new hobbyId (from user/123/hobby/456 to user/123/hobby/789)
  2. Update the data on the HobbyComponent to display the requested hobby

When the button on the UserComponent is clicked, the route works correctly and the HobbyComponent is displayed with no problem. I have an issue with updating the child route. If I add this.route.navigate function into the HobbyComponent to update the child route, the route changes incorrectly: it doesn't replace the hobbyId in the route, instead, it appends a new one -> user/123/hobby/456/789 and the app breaks after that because this route doesn't exist. How to fix that? I want to avoid passing a route change event into the UserComponent, because the components don't have parent-child relationships so I don't see an easy way to pass the event.

Routes:

export const UserRoutes: Routes = [
   { path: 'user/:userId', component: UserComponent, children: [
       { path: 'hobby/:hobbyId', component: HobbyComponent},
   ]}
]

UserComponent:

// button click event
openHobby() {
  this.router.navigate([this.hobbyId], {relativeTo: this.activatedRoute});
}

HobbyComponent:

navigateToNextHobby(nextHobbyId) {
   this.router.navigate([nextHobbyId], {relativeTo: this.activatedRoute});
}

Solution

  • I set up a simple Stackblitz project here that demonstrates a similar scenario. Notice that you can navigate from one hobby to another sibling hobby under the same user.

    My routes are:

    const routes: Routes = [
      {
        path: "user/:userId",
        component: UserComponent,
        children: [{ path: "hobby/:hobbyId", component: HobbyComponent }]
      }
    ];
    

    HTML:

    <button (click)="gotoHobby(1)">Go to hobby 1</button>
    

    Navigation from user to hobby code is:

      async gotoHobby(hobbyId: number): Promise<void> {
        await this.router.navigate(['hobby', hobbyId], { relativeTo: this.route })
      }
    

    Navigation from hobby to hobby:

    HTML:

    <button *ngIf="hobbyId === '1'" (click)="gotoHobby(2)">Go to hobby 2</button>
    <button *ngIf="hobbyId === '2'" (click)="gotoHobby(1)">Go to hobby 1</button>
    

    code:

      async gotoHobby(hobbyId: number): Promise<void> {
        await this.router.navigate(["hobby", hobbyId], {
          relativeTo: this.route.parent
        });
      }