refactor(router): cleanup, simplification
This commit is contained in:
		
							parent
							
								
									6cb93c1fac
								
							
						
					
					
						commit
						81ca51a8f0
					
				| @ -37,8 +37,9 @@ import {PRIMARY_OUTLET} from '../shared'; | ||||
|  */ | ||||
| @Directive({selector: 'router-outlet'}) | ||||
| export class RouterOutlet implements OnDestroy { | ||||
|   private activated: ComponentRef<any>; | ||||
|   private _activatedRoute: ActivatedRoute; | ||||
|   private activated: ComponentRef<any>|null = null; | ||||
|   private _activatedRoute: ActivatedRoute|null = null; | ||||
|   private _outletName: string; | ||||
|   public outletMap: RouterOutletMap; | ||||
| 
 | ||||
|   @Output('activate') activateEvents = new EventEmitter<any>(); | ||||
| @ -46,11 +47,12 @@ export class RouterOutlet implements OnDestroy { | ||||
| 
 | ||||
|   constructor( | ||||
|       private parentOutletMap: RouterOutletMap, private location: ViewContainerRef, | ||||
|       private resolver: ComponentFactoryResolver, @Attribute('name') private name: string) { | ||||
|     parentOutletMap.registerOutlet(name ? name : PRIMARY_OUTLET, this); | ||||
|       private resolver: ComponentFactoryResolver, @Attribute('name') name: string) { | ||||
|     this._outletName = name || PRIMARY_OUTLET; | ||||
|     parentOutletMap.registerOutlet(this._outletName, this); | ||||
|   } | ||||
| 
 | ||||
|   ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this.name ? this.name : PRIMARY_OUTLET); } | ||||
|   ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this._outletName); } | ||||
| 
 | ||||
|   /** @deprecated since v4 **/ | ||||
|   get locationInjector(): Injector { return this.location.injector; } | ||||
| @ -58,24 +60,32 @@ export class RouterOutlet implements OnDestroy { | ||||
|   get locationFactoryResolver(): ComponentFactoryResolver { return this.resolver; } | ||||
| 
 | ||||
|   get isActivated(): boolean { return !!this.activated; } | ||||
| 
 | ||||
|   get component(): Object { | ||||
|     if (!this.activated) throw new Error('Outlet is not activated'); | ||||
|     return this.activated.instance; | ||||
|   } | ||||
| 
 | ||||
|   get activatedRoute(): ActivatedRoute { | ||||
|     if (!this.activated) throw new Error('Outlet is not activated'); | ||||
|     return this._activatedRoute; | ||||
|     return this._activatedRoute as ActivatedRoute; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Called when the `RouteReuseStrategy` instructs to detach the subtree | ||||
|    */ | ||||
|   detach(): ComponentRef<any> { | ||||
|     if (!this.activated) throw new Error('Outlet is not activated'); | ||||
|     this.location.detach(); | ||||
|     const r = this.activated; | ||||
|     this.activated = null !; | ||||
|     this._activatedRoute = null !; | ||||
|     return r; | ||||
|     const cmp = this.activated; | ||||
|     this.activated = null; | ||||
|     this._activatedRoute = null; | ||||
|     return cmp; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree | ||||
|    */ | ||||
|   attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute) { | ||||
|     this.activated = ref; | ||||
|     this._activatedRoute = activatedRoute; | ||||
| @ -86,8 +96,8 @@ export class RouterOutlet implements OnDestroy { | ||||
|     if (this.activated) { | ||||
|       const c = this.component; | ||||
|       this.activated.destroy(); | ||||
|       this.activated = null !; | ||||
|       this._activatedRoute = null !; | ||||
|       this.activated = null; | ||||
|       this._activatedRoute = null; | ||||
|       this.deactivateEvents.emit(c); | ||||
|     } | ||||
|   } | ||||
| @ -129,11 +139,11 @@ export class RouterOutlet implements OnDestroy { | ||||
|     const component = <any>snapshot._routeConfig !.component; | ||||
| 
 | ||||
|     resolver = resolver || this.resolver; | ||||
|     const factory = resolver.resolveComponentFactory(component) !; | ||||
|     const factory = resolver.resolveComponentFactory(component); | ||||
| 
 | ||||
|     const injector = new OutletInjector(activatedRoute, outletMap, this.location.injector); | ||||
| 
 | ||||
|     this.activated = this.location.createComponent(factory, this.location.length, injector, []); | ||||
|     this.activated = this.location.createComponent(factory, this.location.length, injector); | ||||
|     this.activated.changeDetectorRef.detectChanges(); | ||||
| 
 | ||||
|     this.activateEvents.emit(this.activated.instance); | ||||
|  | ||||
| @ -43,7 +43,7 @@ class Recognizer { | ||||
| 
 | ||||
|       const rootNode = new TreeNode<ActivatedRouteSnapshot>(root, children); | ||||
|       const routeState = new RouterStateSnapshot(this.url, rootNode); | ||||
|       this.inheriteParamsAndData(routeState._root); | ||||
|       this.inheritParamsAndData(routeState._root); | ||||
|       return of (routeState); | ||||
| 
 | ||||
|     } catch (e) { | ||||
| @ -52,14 +52,14 @@ class Recognizer { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   inheriteParamsAndData(routeNode: TreeNode<ActivatedRouteSnapshot>): void { | ||||
|   inheritParamsAndData(routeNode: TreeNode<ActivatedRouteSnapshot>): void { | ||||
|     const route = routeNode.value; | ||||
| 
 | ||||
|     const i = inheritedParamsDataResolve(route); | ||||
|     route.params = Object.freeze(i.params); | ||||
|     route.data = Object.freeze(i.data); | ||||
| 
 | ||||
|     routeNode.children.forEach(n => this.inheriteParamsAndData(n)); | ||||
|     routeNode.children.forEach(n => this.inheritParamsAndData(n)); | ||||
|   } | ||||
| 
 | ||||
|   processSegmentGroup(config: Route[], segmentGroup: UrlSegmentGroup, outlet: string): | ||||
|  | ||||
| @ -47,4 +47,17 @@ export abstract class RouteReuseStrategy { | ||||
| 
 | ||||
|   /** Determines if a route should be reused */ | ||||
|   abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean; | ||||
| } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Does not detach any subtrees. Reuses routes as long as their route config is the same. | ||||
|  */ | ||||
| export class DefaultRouteReuseStrategy implements RouteReuseStrategy { | ||||
|   shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; } | ||||
|   store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {} | ||||
|   shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; } | ||||
|   retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; } | ||||
|   shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { | ||||
|     return future.routeConfig === curr.routeConfig; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -28,7 +28,7 @@ import {createUrlTree} from './create_url_tree'; | ||||
| import {RouterOutlet} from './directives/router_outlet'; | ||||
| import {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events'; | ||||
| import {recognize} from './recognize'; | ||||
| import {DetachedRouteHandle, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy'; | ||||
| import {DefaultRouteReuseStrategy, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy'; | ||||
| import {RouterConfigLoader} from './router_config_loader'; | ||||
| import {RouterOutletMap} from './router_outlet_map'; | ||||
| import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState, equalParamsAndUrlSegments, inheritedParamsDataResolve} from './router_state'; | ||||
| @ -192,19 +192,6 @@ function defaultRouterHook(snapshot: RouterStateSnapshot): Observable<void> { | ||||
|   return of (null) as any; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Does not detach any subtrees. Reuses routes as long as their route config is the same. | ||||
|  */ | ||||
| export class DefaultRouteReuseStrategy implements RouteReuseStrategy { | ||||
|   shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; } | ||||
|   store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {} | ||||
|   shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; } | ||||
|   retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; } | ||||
|   shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { | ||||
|     return future.routeConfig === curr.routeConfig; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @whatItDoes Provides the navigation and url manipulation capabilities. | ||||
|  * | ||||
| @ -493,10 +480,10 @@ export class Router { | ||||
|   isActive(url: string|UrlTree, exact: boolean): boolean { | ||||
|     if (url instanceof UrlTree) { | ||||
|       return containsTree(this.currentUrlTree, url, exact); | ||||
|     } else { | ||||
|       const urlTree = this.urlSerializer.parse(url); | ||||
|       return containsTree(this.currentUrlTree, urlTree, exact); | ||||
|     } | ||||
| 
 | ||||
|     const urlTree = this.urlSerializer.parse(url); | ||||
|     return containsTree(this.currentUrlTree, urlTree, exact); | ||||
|   } | ||||
| 
 | ||||
|   private removeEmptyProps(params: Params): Params { | ||||
| @ -637,6 +624,7 @@ export class Router { | ||||
| 
 | ||||
|       // run preactivation: guards and data resolvers
 | ||||
|       let preActivation: PreActivation; | ||||
| 
 | ||||
|       const preactivationTraverse$ = map.call( | ||||
|           beforePreactivationDone$, | ||||
|           ({appliedUrl, snapshot}: {appliedUrl: string, snapshot: RouterStateSnapshot}) => { | ||||
| @ -771,10 +759,10 @@ class CanDeactivate { | ||||
|   constructor(public component: Object|null, public route: ActivatedRouteSnapshot) {} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export class PreActivation { | ||||
|   private canActivateChecks: CanActivate[] = []; | ||||
|   private canDeactivateChecks: CanDeactivate[] = []; | ||||
| 
 | ||||
|   constructor( | ||||
|       private future: RouterStateSnapshot, private curr: RouterStateSnapshot, | ||||
|       private moduleInjector: Injector) {} | ||||
| @ -808,13 +796,16 @@ export class PreActivation { | ||||
|       outletMap: RouterOutletMap|null, futurePath: ActivatedRouteSnapshot[]): void { | ||||
|     const prevChildren = nodeChildrenAsMap(currNode); | ||||
| 
 | ||||
|     // Process the children of the future route
 | ||||
|     futureNode.children.forEach(c => { | ||||
|       this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap, futurePath.concat([c.value])); | ||||
|       delete prevChildren[c.value.outlet]; | ||||
|     }); | ||||
| 
 | ||||
|     // Process any children left from the current route (not active for the future route)
 | ||||
|     forEach( | ||||
|         prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => | ||||
|                           this.deactiveRouteAndItsChildren(v, outletMap !._outlets[k])); | ||||
|                           this.deactivateRouteAndItsChildren(v, outletMap !._outlets[k])); | ||||
|   } | ||||
| 
 | ||||
|   private traverseRoutes( | ||||
| @ -847,7 +838,7 @@ export class PreActivation { | ||||
|       } | ||||
|     } else { | ||||
|       if (curr) { | ||||
|         this.deactiveRouteAndItsChildren(currNode, outlet); | ||||
|         this.deactivateRouteAndItsChildren(currNode, outlet); | ||||
|       } | ||||
| 
 | ||||
|       this.canActivateChecks.push(new CanActivate(futurePath)); | ||||
| @ -879,18 +870,18 @@ export class PreActivation { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private deactiveRouteAndItsChildren( | ||||
|   private deactivateRouteAndItsChildren( | ||||
|       route: TreeNode<ActivatedRouteSnapshot>, outlet: RouterOutlet|null): void { | ||||
|     const prevChildren = nodeChildrenAsMap(route); | ||||
|     const r = route.value; | ||||
| 
 | ||||
|     forEach(prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => { | ||||
|       if (!r.component) { | ||||
|         this.deactiveRouteAndItsChildren(v, outlet); | ||||
|       } else if (!!outlet) { | ||||
|         this.deactiveRouteAndItsChildren(v, outlet.outletMap._outlets[k]); | ||||
|         this.deactivateRouteAndItsChildren(v, outlet); | ||||
|       } else if (outlet) { | ||||
|         this.deactivateRouteAndItsChildren(v, outlet.outletMap._outlets[k]); | ||||
|       } else { | ||||
|         this.deactiveRouteAndItsChildren(v, null); | ||||
|         this.deactivateRouteAndItsChildren(v, null); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
| @ -1020,74 +1011,112 @@ class ActivateRoutes { | ||||
|     this.activateChildRoutes(futureRoot, currRoot, parentOutletMap); | ||||
|   } | ||||
| 
 | ||||
|   // De-activate the child route that are not re-used for the future state
 | ||||
|   private deactivateChildRoutes( | ||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null, | ||||
|       outletMap: RouterOutletMap): void { | ||||
|     const prevChildren: {[key: string]: any} = nodeChildrenAsMap(currNode); | ||||
|     futureNode.children.forEach(c => { | ||||
|       this.deactivateRoutes(c, prevChildren[c.value.outlet], outletMap); | ||||
|       delete prevChildren[c.value.outlet]; | ||||
|     const prevChildren: {[outlet: string]: any} = nodeChildrenAsMap(currNode); | ||||
| 
 | ||||
|     // Recurse on the routes active in the future state to de-activate deeper children
 | ||||
|     futureNode.children.forEach(child => { | ||||
|       const childOutletName = child.value.outlet; | ||||
|       this.deactivateRoutes(child, prevChildren[childOutletName], outletMap); | ||||
|       delete prevChildren[childOutletName]; | ||||
|     }); | ||||
|     forEach(prevChildren, (v: any, k: string) => this.deactiveRouteAndItsChildren(v, outletMap)); | ||||
| 
 | ||||
|     // De-activate the routes that will not be re-used
 | ||||
|     forEach(prevChildren, (v: any, k: string) => this.deactivateRouteAndItsChildren(v, outletMap)); | ||||
|   } | ||||
| 
 | ||||
|   private deactivateRoutes( | ||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, | ||||
|       parentOutletMap: RouterOutletMap): void { | ||||
|     const future = futureNode.value; | ||||
|     const curr = currNode ? currNode.value : null; | ||||
| 
 | ||||
|     if (future === curr) { | ||||
|       // Reusing the node, check to see of the children need to be de-activated
 | ||||
|       if (future.component) { | ||||
|         // If we have a normal route, we need to go through an outlet.
 | ||||
|         const outlet = getOutlet(parentOutletMap, future); | ||||
|         this.deactivateChildRoutes(futureNode, currNode, outlet.outletMap); | ||||
|       } else { | ||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||
|         this.deactivateChildRoutes(futureNode, currNode, parentOutletMap); | ||||
|       } | ||||
|     } else { | ||||
|       if (curr) { | ||||
|         this.deactivateRouteAndItsChildren(currNode, parentOutletMap); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private deactivateRouteAndItsChildren( | ||||
|       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||
|     if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) { | ||||
|       this.detachAndStoreRouteSubtree(route, parentOutletMap); | ||||
|     } else { | ||||
|       this.deactivateRouteAndOutlet(route, parentOutletMap); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private detachAndStoreRouteSubtree( | ||||
|       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||
|     const outlet = getOutlet(parentOutletMap, route.value); | ||||
|     const componentRef = outlet.detach(); | ||||
|     this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route}); | ||||
|   } | ||||
| 
 | ||||
|   private deactivateRouteAndOutlet( | ||||
|       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||
|     const prevChildren: {[outletName: string]: any} = nodeChildrenAsMap(route); | ||||
|     let outlet: RouterOutlet; | ||||
| 
 | ||||
|     // getOutlet throws when cannot find the right outlet,
 | ||||
|     // which can happen if an outlet was in an NgIf and was removed
 | ||||
|     try { | ||||
|       outlet = getOutlet(parentOutletMap, route.value); | ||||
|     } catch (e) { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     const outletMap = route.value.component ? outlet.outletMap : parentOutletMap; | ||||
| 
 | ||||
|     forEach( | ||||
|         prevChildren, (v: any, k: string) => { this.deactivateRouteAndItsChildren(v, outletMap); }); | ||||
| 
 | ||||
|     outlet.deactivate(); | ||||
|   } | ||||
| 
 | ||||
|   private activateChildRoutes( | ||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null, | ||||
|       outletMap: RouterOutletMap): void { | ||||
|     const prevChildren: {[key: string]: any} = nodeChildrenAsMap(currNode); | ||||
|     const prevChildren: {[outlet: string]: any} = nodeChildrenAsMap(currNode); | ||||
|     futureNode.children.forEach( | ||||
|         c => { this.activateRoutes(c, prevChildren[c.value.outlet], outletMap); }); | ||||
|   } | ||||
| 
 | ||||
|   deactivateRoutes( | ||||
|   private activateRoutes( | ||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, | ||||
|       parentOutletMap: RouterOutletMap): void { | ||||
|     const future = futureNode.value; | ||||
|     const curr = currNode ? currNode.value : null; | ||||
| 
 | ||||
|     // reusing the node
 | ||||
|     if (future === curr) { | ||||
|       // If we have a normal route, we need to go through an outlet.
 | ||||
|       if (future.component) { | ||||
|         const outlet = getOutlet(parentOutletMap, future); | ||||
|         this.deactivateChildRoutes(futureNode, currNode, outlet.outletMap); | ||||
| 
 | ||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||
|       } else { | ||||
|         this.deactivateChildRoutes(futureNode, currNode, parentOutletMap); | ||||
|       } | ||||
|     } else { | ||||
|       if (curr) { | ||||
|         this.deactiveRouteAndItsChildren(currNode, parentOutletMap); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   activateRoutes( | ||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, | ||||
|       parentOutletMap: RouterOutletMap): void { | ||||
|     const future = futureNode.value; | ||||
|     const curr = currNode ? currNode.value : null; | ||||
|     advanceActivatedRoute(future); | ||||
| 
 | ||||
|     // reusing the node
 | ||||
|     if (future === curr) { | ||||
|       // advance the route to push the parameters
 | ||||
|       advanceActivatedRoute(future); | ||||
| 
 | ||||
|       // If we have a normal route, we need to go through an outlet.
 | ||||
|       if (future.component) { | ||||
|         // If we have a normal route, we need to go through an outlet.
 | ||||
|         const outlet = getOutlet(parentOutletMap, future); | ||||
|         this.activateChildRoutes(futureNode, currNode, outlet.outletMap); | ||||
| 
 | ||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||
|       } else { | ||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||
|         this.activateChildRoutes(futureNode, currNode, parentOutletMap); | ||||
|       } | ||||
|     } else { | ||||
|       // if we have a normal route, we need to advance the route
 | ||||
|       // and place the component into the outlet. After that recurse.
 | ||||
|       if (future.component) { | ||||
|         advanceActivatedRoute(future); | ||||
|         // if we have a normal route, we need to place the component into the outlet and recurse.
 | ||||
|         const outlet = getOutlet(parentOutletMap, futureNode.value); | ||||
| 
 | ||||
|         if (this.routeReuseStrategy.shouldAttach(future.snapshot)) { | ||||
| @ -1101,10 +1130,8 @@ class ActivateRoutes { | ||||
|           this.placeComponentIntoOutlet(outletMap, future, outlet); | ||||
|           this.activateChildRoutes(futureNode, null, outletMap); | ||||
|         } | ||||
| 
 | ||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||
|       } else { | ||||
|         advanceActivatedRoute(future); | ||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||
|         this.activateChildRoutes(futureNode, null, parentOutletMap); | ||||
|       } | ||||
|     } | ||||
| @ -1117,49 +1144,6 @@ class ActivateRoutes { | ||||
| 
 | ||||
|     outlet.activateWith(future, cmpFactoryResolver, outletMap); | ||||
|   } | ||||
| 
 | ||||
|   private deactiveRouteAndItsChildren( | ||||
|       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||
|     if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) { | ||||
|       this.detachAndStoreRouteSubtree(route, parentOutletMap); | ||||
|     } else { | ||||
|       this.deactiveRouteAndOutlet(route, parentOutletMap); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private detachAndStoreRouteSubtree( | ||||
|       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||
|     const outlet = getOutlet(parentOutletMap, route.value); | ||||
|     const componentRef = outlet.detach(); | ||||
|     this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route}); | ||||
|   } | ||||
| 
 | ||||
|   private deactiveRouteAndOutlet(route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): | ||||
|       void { | ||||
|     const prevChildren: {[key: string]: any} = nodeChildrenAsMap(route); | ||||
|     let outlet: RouterOutlet|null = null; | ||||
| 
 | ||||
|     // getOutlet throws when cannot find the right outlet,
 | ||||
|     // which can happen if an outlet was in an NgIf and was removed
 | ||||
|     try { | ||||
|       outlet = getOutlet(parentOutletMap, route.value); | ||||
|     } catch (e) { | ||||
|       return; | ||||
|     } | ||||
|     const childOutletMap = outlet.outletMap; | ||||
| 
 | ||||
|     forEach(prevChildren, (v: any, k: string) => { | ||||
|       if (route.value.component) { | ||||
|         this.deactiveRouteAndItsChildren(v, childOutletMap); | ||||
|       } else { | ||||
|         this.deactiveRouteAndItsChildren(v, parentOutletMap); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     if (outlet && outlet.isActivated) { | ||||
|       outlet.deactivate(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>): void { | ||||
| @ -1188,8 +1172,9 @@ function closestLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConf | ||||
|   return null; | ||||
| } | ||||
| 
 | ||||
| // Return the list of T indexed by outlet name
 | ||||
| function nodeChildrenAsMap<T extends{outlet: string}>(node: TreeNode<T>| null) { | ||||
|   const map: {[key: string]: TreeNode<T>} = {}; | ||||
|   const map: {[outlet: string]: TreeNode<T>} = {}; | ||||
| 
 | ||||
|   if (node) { | ||||
|     node.children.forEach(child => map[child.value.outlet] = child); | ||||
|  | ||||
| @ -25,5 +25,5 @@ export class RouterOutletMap { | ||||
|   /** | ||||
|    * Removes an outlet from this map. | ||||
|    */ | ||||
|   removeOutlet(name: string): void { this._outlets[name] = undefined !; } | ||||
|   removeOutlet(name: string): void { this._outlets[name] = undefined as any; } | ||||
| } | ||||
|  | ||||
| @ -51,7 +51,7 @@ export class RouterState extends Tree<ActivatedRoute> { | ||||
|       /** The current snapshot of the router state */ | ||||
|       public snapshot: RouterStateSnapshot) { | ||||
|     super(root); | ||||
|     setRouterStateSnapshot<RouterState, ActivatedRoute>(this, root); | ||||
|     setRouterState(<RouterState>this, root); | ||||
|   } | ||||
| 
 | ||||
|   toString(): string { return this.snapshot.toString(); } | ||||
| @ -343,15 +343,15 @@ export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> { | ||||
|       /** The url from which this snapshot was created */ | ||||
|       public url: string, root: TreeNode<ActivatedRouteSnapshot>) { | ||||
|     super(root); | ||||
|     setRouterStateSnapshot<RouterStateSnapshot, ActivatedRouteSnapshot>(this, root); | ||||
|     setRouterState(<RouterStateSnapshot>this, root); | ||||
|   } | ||||
| 
 | ||||
|   toString(): string { return serializeNode(this._root); } | ||||
| } | ||||
| 
 | ||||
| function setRouterStateSnapshot<U, T extends{_routerState: U}>(state: U, node: TreeNode<T>): void { | ||||
| function setRouterState<U, T extends{_routerState: U}>(state: U, node: TreeNode<T>): void { | ||||
|   node.value._routerState = state; | ||||
|   node.children.forEach(c => setRouterStateSnapshot(state, c)); | ||||
|   node.children.forEach(c => setRouterState(state, c)); | ||||
| } | ||||
| 
 | ||||
| function serializeNode(node: TreeNode<ActivatedRouteSnapshot>): string { | ||||
| @ -367,21 +367,22 @@ function serializeNode(node: TreeNode<ActivatedRouteSnapshot>): string { | ||||
| export function advanceActivatedRoute(route: ActivatedRoute): void { | ||||
|   if (route.snapshot) { | ||||
|     const currentSnapshot = route.snapshot; | ||||
|     route.snapshot = route._futureSnapshot; | ||||
|     if (!shallowEqual(currentSnapshot.queryParams, route._futureSnapshot.queryParams)) { | ||||
|       (<any>route.queryParams).next(route._futureSnapshot.queryParams); | ||||
|     const nextSnapshot = route._futureSnapshot; | ||||
|     route.snapshot = nextSnapshot; | ||||
|     if (!shallowEqual(currentSnapshot.queryParams, nextSnapshot.queryParams)) { | ||||
|       (<any>route.queryParams).next(nextSnapshot.queryParams); | ||||
|     } | ||||
|     if (currentSnapshot.fragment !== route._futureSnapshot.fragment) { | ||||
|       (<any>route.fragment).next(route._futureSnapshot.fragment); | ||||
|     if (currentSnapshot.fragment !== nextSnapshot.fragment) { | ||||
|       (<any>route.fragment).next(nextSnapshot.fragment); | ||||
|     } | ||||
|     if (!shallowEqual(currentSnapshot.params, route._futureSnapshot.params)) { | ||||
|       (<any>route.params).next(route._futureSnapshot.params); | ||||
|     if (!shallowEqual(currentSnapshot.params, nextSnapshot.params)) { | ||||
|       (<any>route.params).next(nextSnapshot.params); | ||||
|     } | ||||
|     if (!shallowEqualArrays(currentSnapshot.url, route._futureSnapshot.url)) { | ||||
|       (<any>route.url).next(route._futureSnapshot.url); | ||||
|     if (!shallowEqualArrays(currentSnapshot.url, nextSnapshot.url)) { | ||||
|       (<any>route.url).next(nextSnapshot.url); | ||||
|     } | ||||
|     if (!shallowEqual(currentSnapshot.data, route._futureSnapshot.data)) { | ||||
|       (<any>route.data).next(route._futureSnapshot.data); | ||||
|     if (!shallowEqual(currentSnapshot.data, nextSnapshot.data)) { | ||||
|       (<any>route.data).next(nextSnapshot.data); | ||||
|     } | ||||
|   } else { | ||||
|     route.snapshot = route._futureSnapshot; | ||||
|  | ||||
| @ -42,7 +42,7 @@ export class Tree<T> { | ||||
|    * @internal | ||||
|    */ | ||||
|   siblings(t: T): T[] { | ||||
|     const p = findPath(t, this._root, []); | ||||
|     const p = findPath(t, this._root); | ||||
|     if (p.length < 2) return []; | ||||
| 
 | ||||
|     const c = p[p.length - 2].children.map(c => c.value); | ||||
| @ -52,26 +52,32 @@ export class Tree<T> { | ||||
|   /** | ||||
|    * @internal | ||||
|    */ | ||||
|   pathFromRoot(t: T): T[] { return findPath(t, this._root, []).map(s => s.value); } | ||||
|   pathFromRoot(t: T): T[] { return findPath(t, this._root).map(s => s.value); } | ||||
| } | ||||
| 
 | ||||
| function findNode<T>(expected: T, c: TreeNode<T>): TreeNode<T>|null { | ||||
|   if (expected === c.value) return c; | ||||
|   for (const cc of c.children) { | ||||
|     const r = findNode(expected, cc); | ||||
|     if (r) return r; | ||||
| 
 | ||||
| // DFS for the node matching the value
 | ||||
| function findNode<T>(value: T, node: TreeNode<T>): TreeNode<T>|null { | ||||
|   if (value === node.value) return node; | ||||
| 
 | ||||
|   for (const child of node.children) { | ||||
|     const node = findNode(value, child); | ||||
|     if (node) return node; | ||||
|   } | ||||
| 
 | ||||
|   return null; | ||||
| } | ||||
| 
 | ||||
| function findPath<T>(expected: T, c: TreeNode<T>, collected: TreeNode<T>[]): TreeNode<T>[] { | ||||
|   collected.push(c); | ||||
|   if (expected === c.value) return collected; | ||||
| // Return the path to the node with the given value using DFS
 | ||||
| function findPath<T>(value: T, node: TreeNode<T>): TreeNode<T>[] { | ||||
|   if (value === node.value) return [node]; | ||||
| 
 | ||||
|   for (const cc of c.children) { | ||||
|     const cloned = collected.slice(0); | ||||
|     const r = findPath(expected, cc, cloned); | ||||
|     if (r.length > 0) return r; | ||||
|   for (const child of node.children) { | ||||
|     const path = findPath(value, child); | ||||
|     if (path.length) { | ||||
|       path.unshift(node); | ||||
|       return path; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return []; | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
| import {Routes} from '../src/config'; | ||||
| import {createRouterState} from '../src/create_router_state'; | ||||
| import {recognize} from '../src/recognize'; | ||||
| import {DefaultRouteReuseStrategy} from '../src/router'; | ||||
| import {DefaultRouteReuseStrategy} from '../src/route_reuse_strategy'; | ||||
| import {ActivatedRoute, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from '../src/router_state'; | ||||
| import {PRIMARY_OUTLET} from '../src/shared'; | ||||
| import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree} from '../src/url_tree'; | ||||
| @ -80,7 +80,6 @@ describe('create router state', () => { | ||||
|     const currP = state.firstChild(state.root) !; | ||||
|     expect(prevP).toBe(currP); | ||||
| 
 | ||||
|     const prevC = prevState.children(prevP); | ||||
|     const currC = state.children(currP); | ||||
| 
 | ||||
|     expect(currP._futureSnapshot.params).toEqual({id: '2', p: '22'}); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user