How to reuse route on query params change, but not on path params change in Angular?

Viewed 553

Say I have 2 routes '/users' and /users/:id. First one renders UserListComponent and second UserViewComponent.

I want to re-render component when navigating from /users/1 to /users/2. And of course if I navigate from /users to /users/1 and vice versa.

But I DON'T want to re-render component if I navigate from /users/1?tab=contacts to /users/1?tab=accounts.

Is there a way to configure router like this for entire application?

--

Update:

I'm importing RouterModule in AppRoutingModule like this:

RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })

I'm using Angular 12

2 Answers

The default behavior of the Angular router is to preserve the current component when the URL matches the current route.

This behavior can be changed by using the onSameUrlNavigation option:

Define what the router should do if it receives a navigation request to the current URL. Default is ignore, which causes the router ignores the navigation. This can disable features such as a "refresh" button. Use this option to configure the behavior when navigating to the current URL. Default is 'ignore'.

Unfortunately, this option is not fine-grained enough to allow reload for path params and ignore for query params.

So you have to subscribe both to the query params and the path params changes with something like this:

constructor(route: ActivatedRoute) { }

ngOnInit() {
  this.renderLogic();
  this.route.params.subscribe(() => this.renderLogic());
  this.route.queryParams.subscribe(() => this.renderLogic());
}

renderLogic() {
  // ...
}

As far as I know, @Guerric P is correct, you can't completely re-render the component selectively like this, at least not without some trickery like subscribing to each event and then possibly blocking it for one scenario and not the other. Feel free to try something like that, but below is an alternative if you make use of resolvers to fetch your data.

What you can do is use runGuardsAndResolvers in your route configuration like so:

const routes = [{
  path: 'team/:id',
  component: Team,
  children: [{
    path: 'user/:name',
    component: User
  }],
  runGuardsAndResolvers: 'pathParamsChange',
  resolvers: {...},
  canActivate: [...]
}]

This will, as the name suggests, run your guard resolver logic again. If you fetch data using resolvers and pass it into your components, you can update what your component displays only when the path or params change.

Related