9

here's my lazy loaded child module:

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(acnpRoutes),
    ....
  ],
  declarations: [...],
  providers: [
    {provide: RouteReuseStrategy, useClass: ACNPReuseStrategy}
  ]
})
export class AddCustomerNaturalPersonModule {
}

routes:

const acnpRoutes: Routes = [
  {
    path: '',
    component: AddCustomerNaturalPersonComponent,
    children: [
      {
        path: 'stepOne',
        component: ACNPStepOneComponent
      },
      {
        path: 'stepTwo',
        component: ACNPStepTwoComponent
      },
    ]
  }
]

And ACPNReuseStrategy:

export class ACNPReuseStrategy implements RouteReuseStrategy {
  handlers: {[key: string]: DetachedRouteHandle} = {}

  shouldDetach(route: ActivatedRouteSnapshot): boolean  {
    console.log(1)
    return true;
  }

  store(route: ActivatedRouteSnapshot, handle: {}): void {
    console.log(2)
  }

  ...

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    console.log(5)
  }
}

Unfortunately, none of these console.logs in ACNPReuseStrategy methods is fired. Why is that? Is reusing components possible in lazy loaded module?

Jarosław Rewers
  • 1,059
  • 3
  • 14
  • 23

2 Answers2

12

TL;DR provide your RouteReuseStrategy in main module instead of child module (app.module.ts by default). Then, assign each route a key in route.data to differentiate your routes.


I also encountered this issue recently. My child module is mounted under the main app routes like this:

..., {    // in app.route.ts
          path: 'apimarket',
          canActivate: [DeveloperResolve],
          loadChildren: './apimarket/apimarket.module#ApiMarketModule'
}

If I provide my customized RouteReuseStrategy in the child module ApiMarketModule, the RouteReuseStrategy will never be constructed.

The solution is to provide your Strategy in main module instead of child module (app.module.ts in my case). Then your RouteReuseStrategy will be constructed correctly.

However, the Strategy won't work as expected due to route.routeConfig.path is relative path because of your sub routes. To fix this, my solution is assign a unique key to my routes like this:

export const apimarketRoutes: Routes = [
    {
        path: '',
        component: ApiMarketComponent,
        data: {
            shouldReuse: true,
            key: 'apimarketroot'
        }
    },
    {
        path: ':id',
        component: ContentPageComponent,
    }
];

Here is my RouteReuseStrategy implementation FYR

export class MyRouteReuseStrategy implements RouteReuseStrategy {
  handlers: {[key: string]: DetachedRouteHandle} = {};

  constructor() {
    console.log('constructed');
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    if (!route.data['shouldReuse']) {
      return null;
    }
    console.log('Attach cached page for: ', route.data['key']);
    return this.handlers[route.data['key']];
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    if (route.data['shouldReuse']) {
      this.handlers[route.data['key']] = handle;
    }
  }

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return !!route.data['shouldReuse'];
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return !!route.data['shouldReuse'] && !!this.handlers[route.data['key']];
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
    return !!future.data['shouldReuse'];
  }
}

(RouteReuseStrategy isn't well documented, my solution may have potential performance issue due to the strategy working on root level. Welcome to discuss :) )

yeze322
  • 693
  • 7
  • 17
  • 1
    This is awesome and must be an accepted answer! It is still relevant today with `Angular 12.x`. My implementation was not working as expected until the `key` part I got to know from this answer. Once the `key` is added it is flawlessly working. Angular documentation is still poor after so may version releases. I hope to submitting a PR soon! – Santhosh John Nov 08 '21 at 14:11
  • Thanks for this answer. You have noticed a significant issue with this feature. Everything just works so great now in my project. – jafar_mnkd Oct 07 '22 at 08:39
3

firstly,you must understand what are future and curr.eg: when you navigate from 127.0.0.1:4200/a to 127.0.0.1:4200/b and now you are in b. the future is 127.0.0.1:4200/a ,curr is b,because the future means that you will come back in the future.

when shouldReuseRoute return false ,future !== curr. that is to say the future is different from the curr,we need reuse the future in the future,then,the future will be detach , store and waiting to be reused. On the contrary, when it returns true, nothing is done because the future is the same as the curr.Imagine when you're in a, you want to go b,a is the future,b is the curr.A and b is the same thing, what is necessary to reuse, detach, store a?

Last,You have to understand the order in which these five methods are executed. eg:

navigate to a
shouldReuseRoute->return true->do nothing

a->b
shouldReuseRoute()->return false->shouldDetach()->return true->store a

then b->a
shouldReuseRoute()->return false->shouldDetach()->return true->store b->retrieve() return a ->attach() a.

Be careful,when b->a,after shouldReuseRoute() return false,These methods are not strictly in the order above. For you to more easily understand this process, I deliberately writed so.But you still follow the above order to understand, this does not have any effect.

For better understanding, you should look at these examples. One of the examples will involve lazy loading.

https://medium.com/@gerasimov.pk/how-to-reuse-rendered-component-in-angular-2-3-with-routereusestrategy-64628e1ca3eb

How to implement RouteReuseStrategy shouldDetach for specific routes in Angular 2

My English is not good,I hope you can understand what I said.

buctwbzs
  • 41
  • 5