Advertisement
Guest User

Untitled

a guest
Jul 28th, 2017
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. We are using Angular 4.1.1 for our app, and we are using the Angular router to navigate between components.
  2. By default, Angular destroys components when you navigate to a new route, and reuses components if you navigate to the same route you’re currently on (even if parameters change).
  3. To illustrate,
  4. /home  ->  /host-receiving = HomeComponent destroyed
  5. /host-receiving/receiving/123456/789  ->  /host-receiving/receiving/987654/321 = ReceivingComponent reused
  6.  
  7. For our purposes, we are performing searches on ‘/host-receiving’, then navigating to ‘/host-receiving/receiving/123456/789’, then navigating back to ‘/host-receiving’.
  8. When we do this, we would like to retain the data on the ‘/host-receiving’ component. This means telling Angular not to destroy the component, but to save it and load it the next time the route is visited.
  9.  
  10. To accomplish this, we implement the RouteReuseStrategy.
  11. This is a class that provides methods which are executed every time a route changes:
  12. • shouldDetach(route: ActivatedRouteSnapshot): boolean
  13. o   Should the current route be detached and saved for reuse? If yes, the ‘store’ function is called
  14. • store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void
  15. o   Saves the given DetachedRouteHandle to a private property
  16. • shouldAttach(route: ActivatedRouteSnapshot): boolean
  17. o   Should the current route be attached from a saved version? If yes, the ‘retrieve’ function is called
  18. • retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle
  19. o   Retrieves a DetachedRouteHandle from the private property
  20. • shouldReuseRoute(curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot): boolean
  21. o   Determines whether or not a route should be reused, or created new
  22.  
  23. As we currently have it set up, this is generally working. The ‘/host-receiving’ component has a property that causes the shouldDetach method to return true, thereby storing the component state for reloading later. Then, any time the current route matches the stored route, it loads the stored version instead of recreating it.
  24.  
  25. Here’s where we’re challenged:
  26. When navigating from ‘/host-receiving/receiving/987654/321’ back to ‘/host-receiving’, the stored component is loaded. This is what we want.
  27. When navigating back to ‘/home’, then forward to ‘/host-receiving’, the stored component is again loaded. This is not what we want. In this case, the component should be reloaded.
  28.  
  29. We should be able to use the shouldReuseRoute method to check if we are navigating from a child route to a parent route (reuse the component in this case), or navigating from a parent to a child (recreate the component in this case). However, the method is being called too many times and with mixed up data, due to an Angular bug. This is causing any comparisons to fail, or to return inconsistent results.
  30.  
  31. Below is the code (imports are excluded):
  32.  
  33. app.module.ts
  34. export function loadCookies(cookieService: CookieService): Function {
  35.                 return () => cookieService.loadCookies()
  36. }
  37.  
  38. @NgModule({
  39.                 imports: [BrowserModule, HttpModule, ModalModule.forRoot(), BootstrapModalModule, BrowserAnimationsModule,
  40.                                 SharedModule, HomeModule, OMSManagementModule, HostReceivingModule, LoginRoutingModule, AppRoutingModule],
  41.                 declarations: [AppComponent, PageNotFoundComponent, BreadcrumbComponent, NavbarComponent, DispatchComponent, LoginComponent],
  42.                 providers: [HttpService, TransformService, CookieService, ModalService,
  43.                 {
  44.                                 provide: APP_INITIALIZER,
  45.                                 useFactory: loadCookies,
  46.                                 deps: [CookieService],
  47.                                 multi: true
  48.                 },
  49.                 {
  50.                                 provide: RouteReuseStrategy,
  51.                                 useClass: CustomReuseStrategy
  52.                 }],
  53.                 bootstrap: [AppComponent]
  54. })
  55. export class AppModule {}
  56.  
  57. host-receiving-routing.module.ts
  58. @NgModule({
  59.                 imports: [RouterModule.forChild([
  60.                                 { path: 'host-receiving', component: HostReceivingComponent, data: { breadcrumb: 'host search', roles: [] }, children: [
  61.                                                 { path: '', component: HostSearchComponent, data: { shouldDetach: true, roles: [] } },
  62.                                                 { path: 'receiving/:id/:job', canDeactivate: [CanDeactivateGuard], component: ReceivingComponent, data: { breadcrumb: 'receiving', roles: [] } }
  63.                                 ]}
  64.                 ])],
  65.                 exports: [RouterModule]
  66. })
  67. export class HostReceivingRoutingModule {}
  68.  
  69. custom-reuse-strategy.ts
  70. export class CustomReuseStrategy implements RouteReuseStrategy {
  71.  
  72.                 handlers: {[key: string]: DetachedRouteHandle} = {}
  73.  
  74.                 shouldDetach(route: ActivatedRouteSnapshot): boolean {
  75.                                 return route.data && (route.data as any).shouldDetach
  76.                 }
  77.  
  78.                 store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
  79.                                 this.handlers[this.getFullUrl(route.pathFromRoot)] = handle
  80.                 }
  81.  
  82.                 shouldAttach(route: ActivatedRouteSnapshot): boolean {
  83.                                 return !!route.routeConfig && !!this.handlers[this.getFullUrl(route.pathFromRoot)]
  84.                 }
  85.  
  86.                 retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
  87.                                 if (!route.routeConfig) return null
  88.                                 return this.handlers[this.getFullUrl(route.pathFromRoot)]
  89.                 }
  90.  
  91.                 shouldReuseRoute(curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot): boolean {
  92.                                 return (future.routeConfig === curr.routeConfig) && (_.includes(this.getFullUrl(future.pathFromRoot), this.getFullUrl(curr.pathFromRoot)))
  93.                 }
  94.  
  95.                 private getFullUrl(routes) {
  96.                                 let url = ""
  97.                                 for (let route of routes) {
  98.                                                 if (route.url.length > 0) {
  99.                                                                 if (url.charAt(url.length - 1) !== '/') url += '/'
  100.                                                                 url += route.url.map(url => url.path).join('/')
  101.                                                 }
  102.                                                 else url += '/'
  103.                                 }
  104.                                 return url
  105.                 }
  106. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement