Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RouteReuseStrategy in child module

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?

like image 429
Jarosław Rewers Avatar asked Apr 19 '17 08:04

Jarosław Rewers


2 Answers

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 :) )

like image 107
yeze322 Avatar answered Oct 21 '22 19:10

yeze322


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.

like image 29
buctwbzs Avatar answered Oct 21 '22 18:10

buctwbzs