Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- We are using Angular 4.1.1 for our app, and we are using the Angular router to navigate between components.
- 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).
- To illustrate,
- /home -> /host-receiving = HomeComponent destroyed
- /host-receiving/receiving/123456/789 -> /host-receiving/receiving/987654/321 = ReceivingComponent reused
- For our purposes, we are performing searches on ‘/host-receiving’, then navigating to ‘/host-receiving/receiving/123456/789’, then navigating back to ‘/host-receiving’.
- 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.
- To accomplish this, we implement the RouteReuseStrategy.
- This is a class that provides methods which are executed every time a route changes:
- • shouldDetach(route: ActivatedRouteSnapshot): boolean
- o Should the current route be detached and saved for reuse? If yes, the ‘store’ function is called
- • store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void
- o Saves the given DetachedRouteHandle to a private property
- • shouldAttach(route: ActivatedRouteSnapshot): boolean
- o Should the current route be attached from a saved version? If yes, the ‘retrieve’ function is called
- • retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle
- o Retrieves a DetachedRouteHandle from the private property
- • shouldReuseRoute(curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot): boolean
- o Determines whether or not a route should be reused, or created new
- 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.
- Here’s where we’re challenged:
- When navigating from ‘/host-receiving/receiving/987654/321’ back to ‘/host-receiving’, the stored component is loaded. This is what we want.
- 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.
- 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.
- Below is the code (imports are excluded):
- app.module.ts
- export function loadCookies(cookieService: CookieService): Function {
- return () => cookieService.loadCookies()
- }
- @NgModule({
- imports: [BrowserModule, HttpModule, ModalModule.forRoot(), BootstrapModalModule, BrowserAnimationsModule,
- SharedModule, HomeModule, OMSManagementModule, HostReceivingModule, LoginRoutingModule, AppRoutingModule],
- declarations: [AppComponent, PageNotFoundComponent, BreadcrumbComponent, NavbarComponent, DispatchComponent, LoginComponent],
- providers: [HttpService, TransformService, CookieService, ModalService,
- {
- provide: APP_INITIALIZER,
- useFactory: loadCookies,
- deps: [CookieService],
- multi: true
- },
- {
- provide: RouteReuseStrategy,
- useClass: CustomReuseStrategy
- }],
- bootstrap: [AppComponent]
- })
- export class AppModule {}
- host-receiving-routing.module.ts
- @NgModule({
- imports: [RouterModule.forChild([
- { path: 'host-receiving', component: HostReceivingComponent, data: { breadcrumb: 'host search', roles: [] }, children: [
- { path: '', component: HostSearchComponent, data: { shouldDetach: true, roles: [] } },
- { path: 'receiving/:id/:job', canDeactivate: [CanDeactivateGuard], component: ReceivingComponent, data: { breadcrumb: 'receiving', roles: [] } }
- ]}
- ])],
- exports: [RouterModule]
- })
- export class HostReceivingRoutingModule {}
- custom-reuse-strategy.ts
- export class CustomReuseStrategy implements RouteReuseStrategy {
- handlers: {[key: string]: DetachedRouteHandle} = {}
- shouldDetach(route: ActivatedRouteSnapshot): boolean {
- return route.data && (route.data as any).shouldDetach
- }
- store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
- this.handlers[this.getFullUrl(route.pathFromRoot)] = handle
- }
- shouldAttach(route: ActivatedRouteSnapshot): boolean {
- return !!route.routeConfig && !!this.handlers[this.getFullUrl(route.pathFromRoot)]
- }
- retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
- if (!route.routeConfig) return null
- return this.handlers[this.getFullUrl(route.pathFromRoot)]
- }
- shouldReuseRoute(curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot): boolean {
- return (future.routeConfig === curr.routeConfig) && (_.includes(this.getFullUrl(future.pathFromRoot), this.getFullUrl(curr.pathFromRoot)))
- }
- private getFullUrl(routes) {
- let url = ""
- for (let route of routes) {
- if (route.url.length > 0) {
- if (url.charAt(url.length - 1) !== '/') url += '/'
- url += route.url.map(url => url.path).join('/')
- }
- else url += '/'
- }
- return url
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement