Search code examples
angular-routingangular-router

how to activate a component each time the parameter in the route that activetes it changes


I read that the router reuses a component and its template if the only thing that changes are the route parameters

Therefore, if the component that is activated executes logic in its ngOnInit () it will only be executed the first time that the route like this activates it http://../projects/12

How can you make that logic execute when switching to path http/../projects/45

In my case I have this project: https://stackblitz.com/edit/planificador?file=src/app/planificador/components/resumen/resumen.component.ts

And when I select a new project only executes ResumenComponent's ngOnInit() method the first time

Thanks


Solution

  • TLDR

    StackBlitz app.


    Explanations

    For this situation, we could use a custom RouteReuseStrategy:

    app.module.ts

    export class CustomRouteReuseStrategy extends BaseRouteReuseStrategy {
      shouldReuseRoute(
        future: ActivatedRouteSnapshot,
        curr: ActivatedRouteSnapshot
      ): boolean {
        const determinantParam = "proyectoId";
    
        if (
          !curr?.routeConfig?.path.includes(determinantParam) ||
          !future?.routeConfig?.path.includes(determinantParam)
        ) {
          return super.shouldReuseRoute(future, curr);
        }
    
        return future.params[determinantParam] === curr.params[determinantParam];
      }
    }
    

    The BaseRouteReuseStrategy is defined here and here is why it didn't create a new component when a new param is used:

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
      return future.routeConfig === curr.routeConfig;
    }
    

    and it returns true because the value of routeConfig from both objects(future and curr) is the first item defined in the Routes array in planificador.module.ts:

    {
      path: '',
      component: PlanificadorAppComponent,
      children: [
        {
          path: ':empleadoId/proyectos',
          component: MainContentComponent,
        },
        {
          path: ':empleadoId/proyectos/:proyectoId',
          component: MainContentComponent,
        }
      ]
    },
    

    As expected, Angular builds the next navigation by traversing the route configurations and by comparing that previous state. This state is defined as a tree, where each notes holds meaningful information. Among this information, there is the params object, whose keys are the params(e.g :proyectoId) and the values are determined by what the URL looks like.

    So, what our custom strategy does it to ensure that if the navigation concerns the route who's path is :empleadoId/proyectos/:proyectoId, then this route(and its component) should be reused only if this condition is true:

    future.params[determinantParam] === curr.params[determinantParam]
    

    Furthermore, if you'd like to read more about Angular Router, you could check out these articles: