"Fossies" - the Fresh Open Source Software Archive

Member "angular-8.2.14/packages/router/src/operators/activate_routes.ts" (13 Nov 2019, 8811 Bytes) of package /linux/www/angular-8.2.14.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**
    2  * @license
    3  * Copyright Google Inc. All Rights Reserved.
    4  *
    5  * Use of this source code is governed by an MIT-style license that can be
    6  * found in the LICENSE file at https://angular.io/license
    7  */
    8 
    9 import {MonoTypeOperatorFunction} from 'rxjs';
   10 import {map} from 'rxjs/operators';
   11 
   12 import {LoadedRouterConfig} from '../config';
   13 import {ActivationEnd, ChildActivationEnd, Event} from '../events';
   14 import {DetachedRouteHandleInternal, RouteReuseStrategy} from '../route_reuse_strategy';
   15 import {NavigationTransition} from '../router';
   16 import {ChildrenOutletContexts} from '../router_outlet_context';
   17 import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, advanceActivatedRoute} from '../router_state';
   18 import {forEach} from '../utils/collection';
   19 import {TreeNode, nodeChildrenAsMap} from '../utils/tree';
   20 
   21 export const activateRoutes =
   22     (rootContexts: ChildrenOutletContexts, routeReuseStrategy: RouteReuseStrategy,
   23      forwardEvent: (evt: Event) => void): MonoTypeOperatorFunction<NavigationTransition> =>
   24         map(t => {
   25           new ActivateRoutes(
   26               routeReuseStrategy, t.targetRouterState !, t.currentRouterState, forwardEvent)
   27               .activate(rootContexts);
   28           return t;
   29         });
   30 
   31 export class ActivateRoutes {
   32   constructor(
   33       private routeReuseStrategy: RouteReuseStrategy, private futureState: RouterState,
   34       private currState: RouterState, private forwardEvent: (evt: Event) => void) {}
   35 
   36   activate(parentContexts: ChildrenOutletContexts): void {
   37     const futureRoot = this.futureState._root;
   38     const currRoot = this.currState ? this.currState._root : null;
   39 
   40     this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
   41     advanceActivatedRoute(this.futureState.root);
   42     this.activateChildRoutes(futureRoot, currRoot, parentContexts);
   43   }
   44 
   45   // De-activate the child route that are not re-used for the future state
   46   private deactivateChildRoutes(
   47       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null,
   48       contexts: ChildrenOutletContexts): void {
   49     const children: {[outletName: string]: TreeNode<ActivatedRoute>} = nodeChildrenAsMap(currNode);
   50 
   51     // Recurse on the routes active in the future state to de-activate deeper children
   52     futureNode.children.forEach(futureChild => {
   53       const childOutletName = futureChild.value.outlet;
   54       this.deactivateRoutes(futureChild, children[childOutletName], contexts);
   55       delete children[childOutletName];
   56     });
   57 
   58     // De-activate the routes that will not be re-used
   59     forEach(children, (v: TreeNode<ActivatedRoute>, childName: string) => {
   60       this.deactivateRouteAndItsChildren(v, contexts);
   61     });
   62   }
   63 
   64   private deactivateRoutes(
   65       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>,
   66       parentContext: ChildrenOutletContexts): void {
   67     const future = futureNode.value;
   68     const curr = currNode ? currNode.value : null;
   69 
   70     if (future === curr) {
   71       // Reusing the node, check to see if the children need to be de-activated
   72       if (future.component) {
   73         // If we have a normal route, we need to go through an outlet.
   74         const context = parentContext.getContext(future.outlet);
   75         if (context) {
   76           this.deactivateChildRoutes(futureNode, currNode, context.children);
   77         }
   78       } else {
   79         // if we have a componentless route, we recurse but keep the same outlet map.
   80         this.deactivateChildRoutes(futureNode, currNode, parentContext);
   81       }
   82     } else {
   83       if (curr) {
   84         // Deactivate the current route which will not be re-used
   85         this.deactivateRouteAndItsChildren(currNode, parentContext);
   86       }
   87     }
   88   }
   89 
   90   private deactivateRouteAndItsChildren(
   91       route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void {
   92     if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
   93       this.detachAndStoreRouteSubtree(route, parentContexts);
   94     } else {
   95       this.deactivateRouteAndOutlet(route, parentContexts);
   96     }
   97   }
   98 
   99   private detachAndStoreRouteSubtree(
  100       route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void {
  101     const context = parentContexts.getContext(route.value.outlet);
  102     if (context && context.outlet) {
  103       const componentRef = context.outlet.detach();
  104       const contexts = context.children.onOutletDeactivated();
  105       this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route, contexts});
  106     }
  107   }
  108 
  109   private deactivateRouteAndOutlet(
  110       route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void {
  111     const context = parentContexts.getContext(route.value.outlet);
  112 
  113     if (context) {
  114       const children: {[outletName: string]: any} = nodeChildrenAsMap(route);
  115       const contexts = route.value.component ? context.children : parentContexts;
  116 
  117       forEach(children, (v: any, k: string) => this.deactivateRouteAndItsChildren(v, contexts));
  118 
  119       if (context.outlet) {
  120         // Destroy the component
  121         context.outlet.deactivate();
  122         // Destroy the contexts for all the outlets that were in the component
  123         context.children.onOutletDeactivated();
  124       }
  125     }
  126   }
  127 
  128   private activateChildRoutes(
  129       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null,
  130       contexts: ChildrenOutletContexts): void {
  131     const children: {[outlet: string]: any} = nodeChildrenAsMap(currNode);
  132     futureNode.children.forEach(c => {
  133       this.activateRoutes(c, children[c.value.outlet], contexts);
  134       this.forwardEvent(new ActivationEnd(c.value.snapshot));
  135     });
  136     if (futureNode.children.length) {
  137       this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
  138     }
  139   }
  140 
  141   private activateRoutes(
  142       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>,
  143       parentContexts: ChildrenOutletContexts): void {
  144     const future = futureNode.value;
  145     const curr = currNode ? currNode.value : null;
  146 
  147     advanceActivatedRoute(future);
  148 
  149     // reusing the node
  150     if (future === curr) {
  151       if (future.component) {
  152         // If we have a normal route, we need to go through an outlet.
  153         const context = parentContexts.getOrCreateContext(future.outlet);
  154         this.activateChildRoutes(futureNode, currNode, context.children);
  155       } else {
  156         // if we have a componentless route, we recurse but keep the same outlet map.
  157         this.activateChildRoutes(futureNode, currNode, parentContexts);
  158       }
  159     } else {
  160       if (future.component) {
  161         // if we have a normal route, we need to place the component into the outlet and recurse.
  162         const context = parentContexts.getOrCreateContext(future.outlet);
  163 
  164         if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
  165           const stored =
  166               (<DetachedRouteHandleInternal>this.routeReuseStrategy.retrieve(future.snapshot));
  167           this.routeReuseStrategy.store(future.snapshot, null);
  168           context.children.onOutletReAttached(stored.contexts);
  169           context.attachRef = stored.componentRef;
  170           context.route = stored.route.value;
  171           if (context.outlet) {
  172             // Attach right away when the outlet has already been instantiated
  173             // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
  174             context.outlet.attach(stored.componentRef, stored.route.value);
  175           }
  176           advanceActivatedRouteNodeAndItsChildren(stored.route);
  177         } else {
  178           const config = parentLoadedConfig(future.snapshot);
  179           const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null;
  180 
  181           context.attachRef = null;
  182           context.route = future;
  183           context.resolver = cmpFactoryResolver;
  184           if (context.outlet) {
  185             // Activate the outlet when it has already been instantiated
  186             // Otherwise it will get activated from its `ngOnInit` when instantiated
  187             context.outlet.activateWith(future, cmpFactoryResolver);
  188           }
  189 
  190           this.activateChildRoutes(futureNode, null, context.children);
  191         }
  192       } else {
  193         // if we have a componentless route, we recurse but keep the same outlet map.
  194         this.activateChildRoutes(futureNode, null, parentContexts);
  195       }
  196     }
  197   }
  198 }
  199 
  200 function advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>): void {
  201   advanceActivatedRoute(node.value);
  202   node.children.forEach(advanceActivatedRouteNodeAndItsChildren);
  203 }
  204 
  205 function parentLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig|null {
  206   for (let s = snapshot.parent; s; s = s.parent) {
  207     const route = s.routeConfig;
  208     if (route && route._loadedConfig) return route._loadedConfig;
  209     if (route && route.component) return null;
  210   }
  211 
  212   return null;
  213 }