revert: refactor(router): don't run the change detection every time an outlet is activated
This reverts commit 198edb31093ffdecfd13aed17967fb02e650cffe.
This commit is contained in:
		
							parent
							
								
									6531806996
								
							
						
					
					
						commit
						a0a6029915
					
				| @ -6,8 +6,8 @@ | |||||||
|  * found in the LICENSE file at https://angular.io/license
 |  * found in the LICENSE file at https://angular.io/license
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef} from '@angular/core'; | import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core'; | ||||||
| import {ChildrenOutletContexts} from '../router_outlet_context'; | import {RouterOutletMap} from '../router_outlet_map'; | ||||||
| import {ActivatedRoute} from '../router_state'; | import {ActivatedRoute} from '../router_state'; | ||||||
| import {PRIMARY_OUTLET} from '../shared'; | import {PRIMARY_OUTLET} from '../shared'; | ||||||
| 
 | 
 | ||||||
| @ -36,39 +36,23 @@ import {PRIMARY_OUTLET} from '../shared'; | |||||||
|  * @stable |  * @stable | ||||||
|  */ |  */ | ||||||
| @Directive({selector: 'router-outlet'}) | @Directive({selector: 'router-outlet'}) | ||||||
| export class RouterOutlet implements OnDestroy, OnInit { | export class RouterOutlet implements OnDestroy { | ||||||
|   private activated: ComponentRef<any>|null = null; |   private activated: ComponentRef<any>|null = null; | ||||||
|   private _activatedRoute: ActivatedRoute|null = null; |   private _activatedRoute: ActivatedRoute|null = null; | ||||||
|   private name: string; |   private _outletName: string; | ||||||
|  |   public outletMap: RouterOutletMap; | ||||||
| 
 | 
 | ||||||
|   @Output('activate') activateEvents = new EventEmitter<any>(); |   @Output('activate') activateEvents = new EventEmitter<any>(); | ||||||
|   @Output('deactivate') deactivateEvents = new EventEmitter<any>(); |   @Output('deactivate') deactivateEvents = new EventEmitter<any>(); | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|       private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef, |       private parentOutletMap: RouterOutletMap, private location: ViewContainerRef, | ||||||
|       private resolver: ComponentFactoryResolver, @Attribute('name') name: string) { |       private resolver: ComponentFactoryResolver, @Attribute('name') name: string) { | ||||||
|     this.name = name || PRIMARY_OUTLET; |     this._outletName = name || PRIMARY_OUTLET; | ||||||
|     parentContexts.onChildOutletCreated(this.name, this); |     parentOutletMap.registerOutlet(this._outletName, this); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnDestroy(): void { this.parentContexts.onChildOutletDestroyed(this.name); } |   ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this._outletName); } | ||||||
| 
 |  | ||||||
|   ngOnInit(): void { |  | ||||||
|     if (!this.activated) { |  | ||||||
|       // If the outlet was not instantiated at the time the route got activated we need to populate
 |  | ||||||
|       // the outlet when it is initialized.
 |  | ||||||
|       const context = this.parentContexts.getContext(this.name); |  | ||||||
|       if (context && context.route) { |  | ||||||
|         if (context.attachRef) { |  | ||||||
|           // `attachRef` is populated when there is an existing component to mount
 |  | ||||||
|           this.attach(context.attachRef, context.route); |  | ||||||
|         } else { |  | ||||||
|           // otherwise the component defined in the configuration is created
 |  | ||||||
|           this.activateWith(context.route, context.resolver || null); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   /** @deprecated since v4 **/ |   /** @deprecated since v4 **/ | ||||||
|   get locationInjector(): Injector { return this.location.injector; } |   get locationInjector(): Injector { return this.location.injector; } | ||||||
| @ -118,34 +102,65 @@ export class RouterOutlet implements OnDestroy, OnInit { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) { |   /** @deprecated since v4, use {@link #activateWith} */ | ||||||
|  |   activate( | ||||||
|  |       activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver, injector: Injector, | ||||||
|  |       providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void { | ||||||
|     if (this.isActivated) { |     if (this.isActivated) { | ||||||
|       throw new Error('Cannot activate an already activated outlet'); |       throw new Error('Cannot activate an already activated outlet'); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     this.outletMap = outletMap; | ||||||
|     this._activatedRoute = activatedRoute; |     this._activatedRoute = activatedRoute; | ||||||
|  | 
 | ||||||
|  |     const snapshot = activatedRoute._futureSnapshot; | ||||||
|  |     const component: any = <any>snapshot._routeConfig !.component; | ||||||
|  |     const factory = resolver.resolveComponentFactory(component) !; | ||||||
|  | 
 | ||||||
|  |     const inj = ReflectiveInjector.fromResolvedProviders(providers, injector); | ||||||
|  | 
 | ||||||
|  |     this.activated = this.location.createComponent(factory, this.location.length, inj, []); | ||||||
|  |     this.activated.changeDetectorRef.detectChanges(); | ||||||
|  | 
 | ||||||
|  |     this.activateEvents.emit(this.activated.instance); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   activateWith( | ||||||
|  |       activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null, | ||||||
|  |       outletMap: RouterOutletMap) { | ||||||
|  |     if (this.isActivated) { | ||||||
|  |       throw new Error('Cannot activate an already activated outlet'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.outletMap = outletMap; | ||||||
|  |     this._activatedRoute = activatedRoute; | ||||||
|  | 
 | ||||||
|     const snapshot = activatedRoute._futureSnapshot; |     const snapshot = activatedRoute._futureSnapshot; | ||||||
|     const component = <any>snapshot._routeConfig !.component; |     const component = <any>snapshot._routeConfig !.component; | ||||||
|  | 
 | ||||||
|     resolver = resolver || this.resolver; |     resolver = resolver || this.resolver; | ||||||
|     const factory = resolver.resolveComponentFactory(component); |     const factory = resolver.resolveComponentFactory(component); | ||||||
|     const childContexts = this.parentContexts.getOrCreateContext(this.name).children; | 
 | ||||||
|     const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector); |     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); |     this.activateEvents.emit(this.activated.instance); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class OutletInjector implements Injector { | class OutletInjector implements Injector { | ||||||
|   constructor( |   constructor( | ||||||
|       private route: ActivatedRoute, private childContexts: ChildrenOutletContexts, |       private route: ActivatedRoute, private map: RouterOutletMap, private parent: Injector) {} | ||||||
|       private parent: Injector) {} |  | ||||||
| 
 | 
 | ||||||
|   get(token: any, notFoundValue?: any): any { |   get(token: any, notFoundValue?: any): any { | ||||||
|     if (token === ActivatedRoute) { |     if (token === ActivatedRoute) { | ||||||
|       return this.route; |       return this.route; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (token === ChildrenOutletContexts) { |     if (token === RouterOutletMap) { | ||||||
|       return this.childContexts; |       return this.map; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return this.parent.get(token, notFoundValue); |     return this.parent.get(token, notFoundValue); | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ export {DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy'; | |||||||
| export {NavigationExtras, Router} from './router'; | export {NavigationExtras, Router} from './router'; | ||||||
| export {ROUTES} from './router_config_loader'; | export {ROUTES} from './router_config_loader'; | ||||||
| export {ExtraOptions, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule, provideRoutes} from './router_module'; | export {ExtraOptions, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule, provideRoutes} from './router_module'; | ||||||
| export {ChildrenOutletContexts, OutletContext} from './router_outlet_context'; | export {RouterOutletMap} from './router_outlet_map'; | ||||||
| export {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader'; | export {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader'; | ||||||
| export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './router_state'; | export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './router_state'; | ||||||
| export {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared'; | export {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared'; | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ | |||||||
| 
 | 
 | ||||||
| import {ComponentRef} from '@angular/core'; | import {ComponentRef} from '@angular/core'; | ||||||
| 
 | 
 | ||||||
| import {OutletContext} from './router_outlet_context'; |  | ||||||
| import {ActivatedRoute, ActivatedRouteSnapshot} from './router_state'; | import {ActivatedRoute, ActivatedRouteSnapshot} from './router_state'; | ||||||
| import {TreeNode} from './utils/tree'; | import {TreeNode} from './utils/tree'; | ||||||
| 
 | 
 | ||||||
| @ -24,7 +23,6 @@ export type DetachedRouteHandle = {}; | |||||||
| 
 | 
 | ||||||
| /** @internal */ | /** @internal */ | ||||||
| export type DetachedRouteHandleInternal = { | export type DetachedRouteHandleInternal = { | ||||||
|   contexts: Map<string, OutletContext>, |  | ||||||
|   componentRef: ComponentRef<any>, |   componentRef: ComponentRef<any>, | ||||||
|   route: TreeNode<ActivatedRoute>, |   route: TreeNode<ActivatedRoute>, | ||||||
| }; | }; | ||||||
| @ -38,11 +36,7 @@ export abstract class RouteReuseStrategy { | |||||||
|   /** Determines if this route (and its subtree) should be detached to be reused later */ |   /** Determines if this route (and its subtree) should be detached to be reused later */ | ||||||
|   abstract shouldDetach(route: ActivatedRouteSnapshot): boolean; |   abstract shouldDetach(route: ActivatedRouteSnapshot): boolean; | ||||||
| 
 | 
 | ||||||
|   /** |   /** Stores the detached route */ | ||||||
|    * Stores the detached route. |  | ||||||
|    * |  | ||||||
|    * Storing a `null` value should erase the previously stored value. |  | ||||||
|    */ |  | ||||||
|   abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle|null): void; |   abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle|null): void; | ||||||
| 
 | 
 | ||||||
|   /** Determines if this route (and its subtree) should be reattached */ |   /** Determines if this route (and its subtree) should be reattached */ | ||||||
|  | |||||||
| @ -25,13 +25,14 @@ import {applyRedirects} from './apply_redirects'; | |||||||
| import {LoadedRouterConfig, QueryParamsHandling, ResolveData, Route, Routes, RunGuardsAndResolvers, validateConfig} from './config'; | import {LoadedRouterConfig, QueryParamsHandling, ResolveData, Route, Routes, RunGuardsAndResolvers, validateConfig} from './config'; | ||||||
| import {createRouterState} from './create_router_state'; | import {createRouterState} from './create_router_state'; | ||||||
| import {createUrlTree} from './create_url_tree'; | import {createUrlTree} from './create_url_tree'; | ||||||
|  | import {RouterOutlet} from './directives/router_outlet'; | ||||||
| import {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events'; | import {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events'; | ||||||
| import {recognize} from './recognize'; | import {recognize} from './recognize'; | ||||||
| import {DefaultRouteReuseStrategy, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy'; | import {DefaultRouteReuseStrategy, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy'; | ||||||
| import {RouterConfigLoader} from './router_config_loader'; | import {RouterConfigLoader} from './router_config_loader'; | ||||||
| import {ChildrenOutletContexts, OutletContext} from './router_outlet_context'; | import {RouterOutletMap} from './router_outlet_map'; | ||||||
| import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState, equalParamsAndUrlSegments, inheritedParamsDataResolve} from './router_state'; | import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState, equalParamsAndUrlSegments, inheritedParamsDataResolve} from './router_state'; | ||||||
| import {Params, isNavigationCancelingError} from './shared'; | import {PRIMARY_OUTLET, Params, isNavigationCancelingError} from './shared'; | ||||||
| import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy'; | import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy'; | ||||||
| import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree'; | import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree'; | ||||||
| import {andObservables, forEach, shallowEqual, waitForMap, wrapIntoObservable} from './utils/collection'; | import {andObservables, forEach, shallowEqual, waitForMap, wrapIntoObservable} from './utils/collection'; | ||||||
| @ -250,7 +251,7 @@ export class Router { | |||||||
|   // TODO: vsavkin make internal after the final is out.
 |   // TODO: vsavkin make internal after the final is out.
 | ||||||
|   constructor( |   constructor( | ||||||
|       private rootComponentType: Type<any>|null, private urlSerializer: UrlSerializer, |       private rootComponentType: Type<any>|null, private urlSerializer: UrlSerializer, | ||||||
|       private rootContexts: ChildrenOutletContexts, private location: Location, injector: Injector, |       private outletMap: RouterOutletMap, private location: Location, injector: Injector, | ||||||
|       loader: NgModuleFactoryLoader, compiler: Compiler, public config: Routes) { |       loader: NgModuleFactoryLoader, compiler: Compiler, public config: Routes) { | ||||||
|     const onLoadStart = (r: Route) => this.triggerEvent(new RouteConfigLoadStart(r)); |     const onLoadStart = (r: Route) => this.triggerEvent(new RouteConfigLoadStart(r)); | ||||||
|     const onLoadEnd = (r: Route) => this.triggerEvent(new RouteConfigLoadEnd(r)); |     const onLoadEnd = (r: Route) => this.triggerEvent(new RouteConfigLoadEnd(r)); | ||||||
| @ -630,7 +631,7 @@ export class Router { | |||||||
|             const moduleInjector = this.ngModule.injector; |             const moduleInjector = this.ngModule.injector; | ||||||
|             preActivation = |             preActivation = | ||||||
|                 new PreActivation(snapshot, this.currentRouterState.snapshot, moduleInjector); |                 new PreActivation(snapshot, this.currentRouterState.snapshot, moduleInjector); | ||||||
|             preActivation.traverse(this.rootContexts); |             preActivation.traverse(this.outletMap); | ||||||
|             return {appliedUrl, snapshot}; |             return {appliedUrl, snapshot}; | ||||||
|           }); |           }); | ||||||
| 
 | 
 | ||||||
| @ -701,7 +702,7 @@ export class Router { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             new ActivateRoutes(this.routeReuseStrategy, state, storedState) |             new ActivateRoutes(this.routeReuseStrategy, state, storedState) | ||||||
|                 .activate(this.rootContexts); |                 .activate(this.outletMap); | ||||||
| 
 | 
 | ||||||
|             navigationIsSuccessful = true; |             navigationIsSuccessful = true; | ||||||
|           }) |           }) | ||||||
| @ -766,10 +767,10 @@ export class PreActivation { | |||||||
|       private future: RouterStateSnapshot, private curr: RouterStateSnapshot, |       private future: RouterStateSnapshot, private curr: RouterStateSnapshot, | ||||||
|       private moduleInjector: Injector) {} |       private moduleInjector: Injector) {} | ||||||
| 
 | 
 | ||||||
|   traverse(parentContexts: ChildrenOutletContexts): void { |   traverse(parentOutletMap: RouterOutletMap): void { | ||||||
|     const futureRoot = this.future._root; |     const futureRoot = this.future._root; | ||||||
|     const currRoot = this.curr ? this.curr._root : null; |     const currRoot = this.curr ? this.curr._root : null; | ||||||
|     this.traverseChildRoutes(futureRoot, currRoot, parentContexts, [futureRoot.value]); |     this.traverseChildRoutes(futureRoot, currRoot, parentOutletMap, [futureRoot.value]); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   checkGuards(): Observable<boolean> { |   checkGuards(): Observable<boolean> { | ||||||
| @ -792,35 +793,34 @@ export class PreActivation { | |||||||
| 
 | 
 | ||||||
|   private traverseChildRoutes( |   private traverseChildRoutes( | ||||||
|       futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null, |       futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null, | ||||||
|       contexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[]): void { |       outletMap: RouterOutletMap|null, futurePath: ActivatedRouteSnapshot[]): void { | ||||||
|     const prevChildren = nodeChildrenAsMap(currNode); |     const prevChildren = nodeChildrenAsMap(currNode); | ||||||
| 
 | 
 | ||||||
|     // Process the children of the future route
 |     // Process the children of the future route
 | ||||||
|     futureNode.children.forEach(c => { |     futureNode.children.forEach(c => { | ||||||
|       this.traverseRoutes(c, prevChildren[c.value.outlet], contexts, futurePath.concat([c.value])); |       this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap, futurePath.concat([c.value])); | ||||||
|       delete prevChildren[c.value.outlet]; |       delete prevChildren[c.value.outlet]; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     // Process any children left from the current route (not active for the future route)
 |     // Process any children left from the current route (not active for the future route)
 | ||||||
|     forEach( |     forEach( | ||||||
|         prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => |         prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => | ||||||
|                           this.deactivateRouteAndItsChildren(v, contexts !.getContext(k))); |                           this.deactivateRouteAndItsChildren(v, outletMap !._outlets[k])); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private traverseRoutes( |   private traverseRoutes( | ||||||
|       futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>, |       futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>, | ||||||
|       parentContexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[]): void { |       parentOutletMap: RouterOutletMap|null, futurePath: ActivatedRouteSnapshot[]): void { | ||||||
|     const future = futureNode.value; |     const future = futureNode.value; | ||||||
|     const curr = currNode ? currNode.value : null; |     const curr = currNode ? currNode.value : null; | ||||||
|     const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null; |     const outlet = parentOutletMap ? parentOutletMap._outlets[futureNode.value.outlet] : null; | ||||||
| 
 | 
 | ||||||
|     // reusing the node
 |     // reusing the node
 | ||||||
|     if (curr && future._routeConfig === curr._routeConfig) { |     if (curr && future._routeConfig === curr._routeConfig) { | ||||||
|       if (this.shouldRunGuardsAndResolvers( |       if (this.shouldRunGuardsAndResolvers( | ||||||
|               curr, future, future._routeConfig !.runGuardsAndResolvers)) { |               curr, future, future._routeConfig !.runGuardsAndResolvers)) { | ||||||
|         this.canActivateChecks.push(new CanActivate(futurePath)); |         this.canActivateChecks.push(new CanActivate(futurePath)); | ||||||
|         const outlet = context !.outlet !; |         this.canDeactivateChecks.push(new CanDeactivate(outlet !.component, curr)); | ||||||
|         this.canDeactivateChecks.push(new CanDeactivate(outlet.component, curr)); |  | ||||||
|       } else { |       } else { | ||||||
|         // we need to set the data
 |         // we need to set the data
 | ||||||
|         future.data = curr.data; |         future.data = curr.data; | ||||||
| @ -830,25 +830,25 @@ export class PreActivation { | |||||||
|       // If we have a component, we need to go through an outlet.
 |       // If we have a component, we need to go through an outlet.
 | ||||||
|       if (future.component) { |       if (future.component) { | ||||||
|         this.traverseChildRoutes( |         this.traverseChildRoutes( | ||||||
|             futureNode, currNode, context ? context.children : null, futurePath); |             futureNode, currNode, outlet ? outlet.outletMap : null, futurePath); | ||||||
| 
 | 
 | ||||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 |         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||||
|       } else { |       } else { | ||||||
|         this.traverseChildRoutes(futureNode, currNode, parentContexts, futurePath); |         this.traverseChildRoutes(futureNode, currNode, parentOutletMap, futurePath); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       if (curr) { |       if (curr) { | ||||||
|         this.deactivateRouteAndItsChildren(currNode, context); |         this.deactivateRouteAndItsChildren(currNode, outlet); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       this.canActivateChecks.push(new CanActivate(futurePath)); |       this.canActivateChecks.push(new CanActivate(futurePath)); | ||||||
|       // If we have a component, we need to go through an outlet.
 |       // If we have a component, we need to go through an outlet.
 | ||||||
|       if (future.component) { |       if (future.component) { | ||||||
|         this.traverseChildRoutes(futureNode, null, context ? context.children : null, futurePath); |         this.traverseChildRoutes(futureNode, null, outlet ? outlet.outletMap : null, futurePath); | ||||||
| 
 | 
 | ||||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 |         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||||
|       } else { |       } else { | ||||||
|         this.traverseChildRoutes(futureNode, null, parentContexts, futurePath); |         this.traverseChildRoutes(futureNode, null, parentOutletMap, futurePath); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -871,24 +871,24 @@ export class PreActivation { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private deactivateRouteAndItsChildren( |   private deactivateRouteAndItsChildren( | ||||||
|       route: TreeNode<ActivatedRouteSnapshot>, context: OutletContext|null): void { |       route: TreeNode<ActivatedRouteSnapshot>, outlet: RouterOutlet|null): void { | ||||||
|     const children = nodeChildrenAsMap(route); |     const prevChildren = nodeChildrenAsMap(route); | ||||||
|     const r = route.value; |     const r = route.value; | ||||||
| 
 | 
 | ||||||
|     forEach(children, (node: TreeNode<ActivatedRouteSnapshot>, childName: string) => { |     forEach(prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => { | ||||||
|       if (!r.component) { |       if (!r.component) { | ||||||
|         this.deactivateRouteAndItsChildren(node, context); |         this.deactivateRouteAndItsChildren(v, outlet); | ||||||
|       } else if (context) { |       } else if (outlet) { | ||||||
|         this.deactivateRouteAndItsChildren(node, context.children.getContext(childName)); |         this.deactivateRouteAndItsChildren(v, outlet.outletMap._outlets[k]); | ||||||
|       } else { |       } else { | ||||||
|         this.deactivateRouteAndItsChildren(node, null); |         this.deactivateRouteAndItsChildren(v, null); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     if (!r.component) { |     if (!r.component) { | ||||||
|       this.canDeactivateChecks.push(new CanDeactivate(null, r)); |       this.canDeactivateChecks.push(new CanDeactivate(null, r)); | ||||||
|     } else if (context && context.outlet && context.outlet.isActivated) { |     } else if (outlet && outlet.isActivated) { | ||||||
|       this.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, r)); |       this.canDeactivateChecks.push(new CanDeactivate(outlet.component, r)); | ||||||
|     } else { |     } else { | ||||||
|       this.canDeactivateChecks.push(new CanDeactivate(null, r)); |       this.canDeactivateChecks.push(new CanDeactivate(null, r)); | ||||||
|     } |     } | ||||||
| @ -1002,109 +1002,103 @@ class ActivateRoutes { | |||||||
|       private routeReuseStrategy: RouteReuseStrategy, private futureState: RouterState, |       private routeReuseStrategy: RouteReuseStrategy, private futureState: RouterState, | ||||||
|       private currState: RouterState) {} |       private currState: RouterState) {} | ||||||
| 
 | 
 | ||||||
|   activate(parentContexts: ChildrenOutletContexts): void { |   activate(parentOutletMap: RouterOutletMap): void { | ||||||
|     const futureRoot = this.futureState._root; |     const futureRoot = this.futureState._root; | ||||||
|     const currRoot = this.currState ? this.currState._root : null; |     const currRoot = this.currState ? this.currState._root : null; | ||||||
| 
 | 
 | ||||||
|     this.deactivateChildRoutes(futureRoot, currRoot, parentContexts); |     this.deactivateChildRoutes(futureRoot, currRoot, parentOutletMap); | ||||||
|     advanceActivatedRoute(this.futureState.root); |     advanceActivatedRoute(this.futureState.root); | ||||||
|     this.activateChildRoutes(futureRoot, currRoot, parentContexts); |     this.activateChildRoutes(futureRoot, currRoot, parentOutletMap); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // De-activate the child route that are not re-used for the future state
 |   // De-activate the child route that are not re-used for the future state
 | ||||||
|   private deactivateChildRoutes( |   private deactivateChildRoutes( | ||||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null, |       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null, | ||||||
|       contexts: ChildrenOutletContexts): void { |       outletMap: RouterOutletMap): void { | ||||||
|     const children: {[outletName: string]: TreeNode<ActivatedRoute>} = nodeChildrenAsMap(currNode); |     const prevChildren: {[outlet: string]: any} = nodeChildrenAsMap(currNode); | ||||||
| 
 | 
 | ||||||
|     // Recurse on the routes active in the future state to de-activate deeper children
 |     // Recurse on the routes active in the future state to de-activate deeper children
 | ||||||
|     futureNode.children.forEach(futureChild => { |     futureNode.children.forEach(child => { | ||||||
|       const childOutletName = futureChild.value.outlet; |       const childOutletName = child.value.outlet; | ||||||
|       this.deactivateRoutes(futureChild, children[childOutletName], contexts); |       this.deactivateRoutes(child, prevChildren[childOutletName], outletMap); | ||||||
|       delete children[childOutletName]; |       delete prevChildren[childOutletName]; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     // De-activate the routes that will not be re-used
 |     // De-activate the routes that will not be re-used
 | ||||||
|     forEach(children, (v: TreeNode<ActivatedRoute>, childName: string) => { |     forEach(prevChildren, (v: any, k: string) => this.deactivateRouteAndItsChildren(v, outletMap)); | ||||||
|       this.deactivateRouteAndItsChildren(v, contexts); |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private deactivateRoutes( |   private deactivateRoutes( | ||||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, |       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, | ||||||
|       parentContext: ChildrenOutletContexts): void { |       parentOutletMap: RouterOutletMap): void { | ||||||
|     const future = futureNode.value; |     const future = futureNode.value; | ||||||
|     const curr = currNode ? currNode.value : null; |     const curr = currNode ? currNode.value : null; | ||||||
| 
 | 
 | ||||||
|     if (future === curr) { |     if (future === curr) { | ||||||
|       // Reusing the node, check to see if the children need to be de-activated
 |       // Reusing the node, check to see of the children need to be de-activated
 | ||||||
|       if (future.component) { |       if (future.component) { | ||||||
|         // If we have a normal route, we need to go through an outlet.
 |         // If we have a normal route, we need to go through an outlet.
 | ||||||
|         const context = parentContext.getContext(future.outlet); |         const outlet = getOutlet(parentOutletMap, future); | ||||||
|         if (context) { |         this.deactivateChildRoutes(futureNode, currNode, outlet.outletMap); | ||||||
|           this.deactivateChildRoutes(futureNode, currNode, context.children); |  | ||||||
|         } |  | ||||||
|       } else { |       } else { | ||||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 |         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||||
|         this.deactivateChildRoutes(futureNode, currNode, parentContext); |         this.deactivateChildRoutes(futureNode, currNode, parentOutletMap); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       if (curr) { |       if (curr) { | ||||||
|         // Deactivate the current route which will not be re-used
 |         this.deactivateRouteAndItsChildren(currNode, parentOutletMap); | ||||||
|         this.deactivateRouteAndItsChildren(currNode, parentContext); |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private deactivateRouteAndItsChildren( |   private deactivateRouteAndItsChildren( | ||||||
|       route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void { |       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||||
|     if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) { |     if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) { | ||||||
|       this.detachAndStoreRouteSubtree(route, parentContexts); |       this.detachAndStoreRouteSubtree(route, parentOutletMap); | ||||||
|     } else { |     } else { | ||||||
|       this.deactivateRouteAndOutlet(route, parentContexts); |       this.deactivateRouteAndOutlet(route, parentOutletMap); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private detachAndStoreRouteSubtree( |   private detachAndStoreRouteSubtree( | ||||||
|       route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void { |       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||||
|     const context = parentContexts.getContext(route.value.outlet); |     const outlet = getOutlet(parentOutletMap, route.value); | ||||||
|     if (context && context.outlet) { |     const componentRef = outlet.detach(); | ||||||
|       const componentRef = context.outlet.detach(); |     this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route}); | ||||||
|       const contexts = context.children.onOutletDeactivated(); |  | ||||||
|       this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route, contexts}); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private deactivateRouteAndOutlet( |   private deactivateRouteAndOutlet( | ||||||
|       route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void { |       route: TreeNode<ActivatedRoute>, parentOutletMap: RouterOutletMap): void { | ||||||
|     const context = parentContexts.getContext(route.value.outlet); |     const prevChildren: {[outletName: string]: any} = nodeChildrenAsMap(route); | ||||||
|  |     let outlet: RouterOutlet; | ||||||
| 
 | 
 | ||||||
|     if (context) { |     // getOutlet throws when cannot find the right outlet,
 | ||||||
|       const children: {[outletName: string]: any} = nodeChildrenAsMap(route); |     // which can happen if an outlet was in an NgIf and was removed
 | ||||||
|       const contexts = route.value.component ? context.children : parentContexts; |     try { | ||||||
| 
 |       outlet = getOutlet(parentOutletMap, route.value); | ||||||
|       forEach(children, (v: any, k: string) => {this.deactivateRouteAndItsChildren(v, contexts)}); |     } catch (e) { | ||||||
| 
 |       return; | ||||||
|       if (context.outlet) { |  | ||||||
|         // Destroy the component
 |  | ||||||
|         context.outlet.deactivate(); |  | ||||||
|         // Destroy the contexts for all the outlets that were in the component
 |  | ||||||
|         context.children.onOutletDeactivated(); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     const outletMap = route.value.component ? outlet.outletMap : parentOutletMap; | ||||||
|  | 
 | ||||||
|  |     forEach( | ||||||
|  |         prevChildren, (v: any, k: string) => { this.deactivateRouteAndItsChildren(v, outletMap); }); | ||||||
|  | 
 | ||||||
|  |     outlet.deactivate(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private activateChildRoutes( |   private activateChildRoutes( | ||||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null, |       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null, | ||||||
|       contexts: ChildrenOutletContexts): void { |       outletMap: RouterOutletMap): void { | ||||||
|     const children: {[outlet: string]: any} = nodeChildrenAsMap(currNode); |     const prevChildren: {[outlet: string]: any} = nodeChildrenAsMap(currNode); | ||||||
|     futureNode.children.forEach( |     futureNode.children.forEach( | ||||||
|         c => { this.activateRoutes(c, children[c.value.outlet], contexts); }); |         c => { this.activateRoutes(c, prevChildren[c.value.outlet], outletMap); }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private activateRoutes( |   private activateRoutes( | ||||||
|       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, |       futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>, | ||||||
|       parentContexts: ChildrenOutletContexts): void { |       parentOutletMap: RouterOutletMap): void { | ||||||
|     const future = futureNode.value; |     const future = futureNode.value; | ||||||
|     const curr = currNode ? currNode.value : null; |     const curr = currNode ? currNode.value : null; | ||||||
| 
 | 
 | ||||||
| @ -1114,50 +1108,42 @@ class ActivateRoutes { | |||||||
|     if (future === curr) { |     if (future === curr) { | ||||||
|       if (future.component) { |       if (future.component) { | ||||||
|         // If we have a normal route, we need to go through an outlet.
 |         // If we have a normal route, we need to go through an outlet.
 | ||||||
|         const context = parentContexts.getOrCreateContext(future.outlet); |         const outlet = getOutlet(parentOutletMap, future); | ||||||
|         this.activateChildRoutes(futureNode, currNode, context.children); |         this.activateChildRoutes(futureNode, currNode, outlet.outletMap); | ||||||
|       } else { |       } else { | ||||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 |         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||||
|         this.activateChildRoutes(futureNode, currNode, parentContexts); |         this.activateChildRoutes(futureNode, currNode, parentOutletMap); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       if (future.component) { |       if (future.component) { | ||||||
|         // if we have a normal route, we need to place the component into the outlet and recurse.
 |         // if we have a normal route, we need to place the component into the outlet and recurse.
 | ||||||
|         const context = parentContexts.getOrCreateContext(future.outlet); |         const outlet = getOutlet(parentOutletMap, futureNode.value); | ||||||
| 
 | 
 | ||||||
|         if (this.routeReuseStrategy.shouldAttach(future.snapshot)) { |         if (this.routeReuseStrategy.shouldAttach(future.snapshot)) { | ||||||
|           const stored = |           const stored = | ||||||
|               (<DetachedRouteHandleInternal>this.routeReuseStrategy.retrieve(future.snapshot)); |               (<DetachedRouteHandleInternal>this.routeReuseStrategy.retrieve(future.snapshot)); | ||||||
|           this.routeReuseStrategy.store(future.snapshot, null); |           this.routeReuseStrategy.store(future.snapshot, null); | ||||||
|           context.children.onOutletReAttached(stored.contexts); |           outlet.attach(stored.componentRef, stored.route.value); | ||||||
|           context.attachRef = stored.componentRef; |  | ||||||
|           context.route = stored.route.value; |  | ||||||
|           if (context.outlet) { |  | ||||||
|             // Attach right away when the outlet has already been instantiated
 |  | ||||||
|             // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
 |  | ||||||
|             context.outlet.attach(stored.componentRef, stored.route.value); |  | ||||||
|           } |  | ||||||
|           advanceActivatedRouteNodeAndItsChildren(stored.route); |           advanceActivatedRouteNodeAndItsChildren(stored.route); | ||||||
|         } else { |         } else { | ||||||
|           const config = parentLoadedConfig(future.snapshot); |           const outletMap = new RouterOutletMap(); | ||||||
|           const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null; |           this.placeComponentIntoOutlet(outletMap, future, outlet); | ||||||
| 
 |           this.activateChildRoutes(futureNode, null, outletMap); | ||||||
|           context.route = future; |  | ||||||
|           context.resolver = cmpFactoryResolver; |  | ||||||
|           if (context.outlet) { |  | ||||||
|             // Activate the outlet when it has already been instantiated
 |  | ||||||
|             // Otherwise it will get activated from its `ngOnInit` when instantiated
 |  | ||||||
|             context.outlet.activateWith(future, cmpFactoryResolver); |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           this.activateChildRoutes(futureNode, null, context.children); |  | ||||||
|         } |         } | ||||||
|       } else { |       } else { | ||||||
|         // if we have a componentless route, we recurse but keep the same outlet map.
 |         // if we have a componentless route, we recurse but keep the same outlet map.
 | ||||||
|         this.activateChildRoutes(futureNode, null, parentContexts); |         this.activateChildRoutes(futureNode, null, parentOutletMap); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   private placeComponentIntoOutlet( | ||||||
|  |       outletMap: RouterOutletMap, future: ActivatedRoute, outlet: RouterOutlet): void { | ||||||
|  |     const config = parentLoadedConfig(future.snapshot); | ||||||
|  |     const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null; | ||||||
|  | 
 | ||||||
|  |     outlet.activateWith(future, cmpFactoryResolver, outletMap); | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>): void { | function advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>): void { | ||||||
| @ -1197,6 +1183,19 @@ function nodeChildrenAsMap<T extends{outlet: string}>(node: TreeNode<T>| null) { | |||||||
|   return map; |   return map; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function getOutlet(outletMap: RouterOutletMap, route: ActivatedRoute): RouterOutlet { | ||||||
|  |   const outlet = outletMap._outlets[route.outlet]; | ||||||
|  |   if (!outlet) { | ||||||
|  |     const componentName = (<any>route.component).name; | ||||||
|  |     if (route.outlet === PRIMARY_OUTLET) { | ||||||
|  |       throw new Error(`Cannot find primary outlet to load '${componentName}'`); | ||||||
|  |     } else { | ||||||
|  |       throw new Error(`Cannot find the outlet ${route.outlet} to load '${componentName}'`); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return outlet; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function validateCommands(commands: string[]): void { | function validateCommands(commands: string[]): void { | ||||||
|   for (let i = 0; i < commands.length; i++) { |   for (let i = 0; i < commands.length; i++) { | ||||||
|     const cmd = commands[i]; |     const cmd = commands[i]; | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ import {RouterOutlet} from './directives/router_outlet'; | |||||||
| import {RouteReuseStrategy} from './route_reuse_strategy'; | import {RouteReuseStrategy} from './route_reuse_strategy'; | ||||||
| import {ErrorHandler, Router} from './router'; | import {ErrorHandler, Router} from './router'; | ||||||
| import {ROUTES} from './router_config_loader'; | import {ROUTES} from './router_config_loader'; | ||||||
| import {ChildrenOutletContexts} from './router_outlet_context'; | import {RouterOutletMap} from './router_outlet_map'; | ||||||
| import {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader'; | import {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader'; | ||||||
| import {ActivatedRoute} from './router_state'; | import {ActivatedRoute} from './router_state'; | ||||||
| import {UrlHandlingStrategy} from './url_handling_strategy'; | import {UrlHandlingStrategy} from './url_handling_strategy'; | ||||||
| @ -51,12 +51,12 @@ export const ROUTER_PROVIDERS: Provider[] = [ | |||||||
|     provide: Router, |     provide: Router, | ||||||
|     useFactory: setupRouter, |     useFactory: setupRouter, | ||||||
|     deps: [ |     deps: [ | ||||||
|       ApplicationRef, UrlSerializer, ChildrenOutletContexts, Location, Injector, |       ApplicationRef, UrlSerializer, RouterOutletMap, Location, Injector, NgModuleFactoryLoader, | ||||||
|       NgModuleFactoryLoader, Compiler, ROUTES, ROUTER_CONFIGURATION, |       Compiler, ROUTES, ROUTER_CONFIGURATION, [UrlHandlingStrategy, new Optional()], | ||||||
|       [UrlHandlingStrategy, new Optional()], [RouteReuseStrategy, new Optional()] |       [RouteReuseStrategy, new Optional()] | ||||||
|     ] |     ] | ||||||
|   }, |   }, | ||||||
|   ChildrenOutletContexts, |   RouterOutletMap, | ||||||
|   {provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]}, |   {provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]}, | ||||||
|   {provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}, |   {provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader}, | ||||||
|   RouterPreloader, |   RouterPreloader, | ||||||
| @ -270,12 +270,12 @@ export interface ExtraOptions { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function setupRouter( | export function setupRouter( | ||||||
|     ref: ApplicationRef, urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, |     ref: ApplicationRef, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, | ||||||
|     location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, |     location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, | ||||||
|     config: Route[][], opts: ExtraOptions = {}, urlHandlingStrategy?: UrlHandlingStrategy, |     config: Route[][], opts: ExtraOptions = {}, urlHandlingStrategy?: UrlHandlingStrategy, | ||||||
|     routeReuseStrategy?: RouteReuseStrategy) { |     routeReuseStrategy?: RouteReuseStrategy) { | ||||||
|   const router = new Router( |   const router = new Router( | ||||||
|       null, urlSerializer, contexts, location, injector, loader, compiler, flatten(config)); |       null, urlSerializer, outletMap, location, injector, loader, compiler, flatten(config)); | ||||||
| 
 | 
 | ||||||
|   if (urlHandlingStrategy) { |   if (urlHandlingStrategy) { | ||||||
|     router.urlHandlingStrategy = urlHandlingStrategy; |     router.urlHandlingStrategy = urlHandlingStrategy; | ||||||
|  | |||||||
| @ -1,80 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @license |  | ||||||
|  * Copyright Google Inc. All Rights Reserved. |  | ||||||
|  * |  | ||||||
|  * Use of this source code is governed by an MIT-style license that can be |  | ||||||
|  * found in the LICENSE file at https://angular.io/license
 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| import {ComponentFactoryResolver, ComponentRef} from '@angular/core'; |  | ||||||
| 
 |  | ||||||
| import {RouterOutlet} from './directives/router_outlet'; |  | ||||||
| import {ActivatedRoute} from './router_state'; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Store contextual information about a {@link RouterOutlet} |  | ||||||
|  * |  | ||||||
|  * @stable |  | ||||||
|  */ |  | ||||||
| export class OutletContext { |  | ||||||
|   outlet: RouterOutlet|null = null; |  | ||||||
|   route: ActivatedRoute|null = null; |  | ||||||
|   resolver: ComponentFactoryResolver|null = null; |  | ||||||
|   children = new ChildrenOutletContexts(); |  | ||||||
|   attachRef: ComponentRef<any>|null = null; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Store contextual information about the children (= nested) {@link RouterOutlet} |  | ||||||
|  * |  | ||||||
|  * @stable |  | ||||||
|  */ |  | ||||||
| export class ChildrenOutletContexts { |  | ||||||
|   // contexts for child outlets, by name.
 |  | ||||||
|   private contexts = new Map<string, OutletContext>(); |  | ||||||
| 
 |  | ||||||
|   /** Called when a `RouterOutlet` directive is instantiated */ |  | ||||||
|   onChildOutletCreated(childName: string, outlet: RouterOutlet): void { |  | ||||||
|     const context = this.getOrCreateContext(childName); |  | ||||||
|     context.outlet = outlet; |  | ||||||
|     this.contexts.set(childName, context); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Called when a `RouterOutlet` directive is destroyed. |  | ||||||
|    * We need to keep the context as the outlet could be destroyed inside a NgIf and might be |  | ||||||
|    * re-created later. |  | ||||||
|    */ |  | ||||||
|   onChildOutletDestroyed(childName: string): void { |  | ||||||
|     const context = this.getContext(childName); |  | ||||||
|     if (context) { |  | ||||||
|       context.outlet = null; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Called when the corresponding route is deactivated during navigation. |  | ||||||
|    * Because the component get destroyed, all children outlet are destroyed. |  | ||||||
|    */ |  | ||||||
|   onOutletDeactivated(): Map<string, OutletContext> { |  | ||||||
|     const contexts = this.contexts; |  | ||||||
|     this.contexts = new Map(); |  | ||||||
|     return contexts; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   onOutletReAttached(contexts: Map<string, OutletContext>) { this.contexts = contexts; } |  | ||||||
| 
 |  | ||||||
|   getOrCreateContext(childName: string): OutletContext { |  | ||||||
|     let context = this.getContext(childName); |  | ||||||
| 
 |  | ||||||
|     if (!context) { |  | ||||||
|       context = new OutletContext(); |  | ||||||
|       this.contexts.set(childName, context); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return context; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   getContext(childName: string): OutletContext|null { return this.contexts.get(childName) || null; } |  | ||||||
| } |  | ||||||
							
								
								
									
										29
									
								
								packages/router/src/router_outlet_map.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								packages/router/src/router_outlet_map.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | /** | ||||||
|  |  * @license | ||||||
|  |  * Copyright Google Inc. All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * Use of this source code is governed by an MIT-style license that can be | ||||||
|  |  * found in the LICENSE file at https://angular.io/license
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | import {RouterOutlet} from './directives/router_outlet'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @whatItDoes Contains all the router outlets created in a component. | ||||||
|  |  * | ||||||
|  |  * @stable | ||||||
|  |  */ | ||||||
|  | export class RouterOutletMap { | ||||||
|  |   /** @internal */ | ||||||
|  |   _outlets: {[name: string]: RouterOutlet} = {}; | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Adds an outlet to this map. | ||||||
|  |    */ | ||||||
|  |   registerOutlet(name: string, outlet: RouterOutlet): void { this._outlets[name] = outlet; } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Removes an outlet from this map. | ||||||
|  |    */ | ||||||
|  |   removeOutlet(name: string): void { this._outlets[name] = undefined as any; } | ||||||
|  | } | ||||||
| @ -120,10 +120,8 @@ describe('Integration', () => { | |||||||
|            router.resetConfig([{ |            router.resetConfig([{ | ||||||
|              path: 'parent/:id', |              path: 'parent/:id', | ||||||
|              component: Parent, |              component: Parent, | ||||||
|              children: [ |              children: | ||||||
|                {path: 'child1', component: Child1}, |                  [{path: 'child1', component: Child1}, {path: 'child2', component: Child2}] | ||||||
|                {path: 'child2', component: Child2}, |  | ||||||
|              ] |  | ||||||
|            }]); |            }]); | ||||||
| 
 | 
 | ||||||
|            router.navigateByUrl('/parent/1/child1'); |            router.navigateByUrl('/parent/1/child1'); | ||||||
| @ -133,18 +131,13 @@ describe('Integration', () => { | |||||||
|            advance(fixture); |            advance(fixture); | ||||||
| 
 | 
 | ||||||
|            expect(location.path()).toEqual('/parent/2/child2'); |            expect(location.path()).toEqual('/parent/2/child2'); | ||||||
|            expect(log).toEqual([ |            expect(log).toEqual([{id: '1'}, 'child1 destroy', {id: '2'}, 'child2 constructor']); | ||||||
|              {id: '1'}, |  | ||||||
|              'child1 destroy', |  | ||||||
|              {id: '2'}, |  | ||||||
|              'child2 constructor', |  | ||||||
|            ]); |  | ||||||
|          }))); |          }))); | ||||||
| 
 | 
 | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     it('should execute navigations serialy', |     it('should execute navigations serialy', | ||||||
|        fakeAsync(inject([Router, Location], (router: Router) => { |        fakeAsync(inject([Router, Location], (router: Router, location: Location) => { | ||||||
|          const fixture = createRoot(router, RootCmp); |          const fixture = createRoot(router, RootCmp); | ||||||
| 
 | 
 | ||||||
|          router.resetConfig([ |          router.resetConfig([ | ||||||
| @ -209,7 +202,7 @@ describe('Integration', () => { | |||||||
| 
 | 
 | ||||||
|        router.resetConfig([{ |        router.resetConfig([{ | ||||||
|          path: 'child', |          path: 'child', | ||||||
|          component: OutletInNgIf, |          component: LinkInNgIf, | ||||||
|          children: [{path: 'simple', component: SimpleCmp}] |          children: [{path: 'simple', component: SimpleCmp}] | ||||||
|        }]); |        }]); | ||||||
| 
 | 
 | ||||||
| @ -219,10 +212,10 @@ describe('Integration', () => { | |||||||
|        expect(location.path()).toEqual('/child/simple'); |        expect(location.path()).toEqual('/child/simple'); | ||||||
|      }))); |      }))); | ||||||
| 
 | 
 | ||||||
|   it('should work when an outlet is added/removed', fakeAsync(() => { |   it('should work when an outlet is in an ngIf (and is removed)', fakeAsync(() => { | ||||||
|        @Component({ |        @Component({ | ||||||
|          selector: 'someRoot', |          selector: 'someRoot', | ||||||
|          template: `[<div *ngIf="cond"><router-outlet></router-outlet></div>]` |          template: `<div *ngIf="cond"><router-outlet></router-outlet></div>` | ||||||
|        }) |        }) | ||||||
|        class RootCmpWithLink { |        class RootCmpWithLink { | ||||||
|          cond: boolean = true; |          cond: boolean = true; | ||||||
| @ -230,25 +223,26 @@ describe('Integration', () => { | |||||||
|        TestBed.configureTestingModule({declarations: [RootCmpWithLink]}); |        TestBed.configureTestingModule({declarations: [RootCmpWithLink]}); | ||||||
| 
 | 
 | ||||||
|        const router: Router = TestBed.get(Router); |        const router: Router = TestBed.get(Router); | ||||||
|  |        const location: Location = TestBed.get(Location); | ||||||
| 
 | 
 | ||||||
|        const fixture = createRoot(router, RootCmpWithLink); |        const fixture = createRoot(router, RootCmpWithLink); | ||||||
| 
 | 
 | ||||||
|        router.resetConfig([ |        router.resetConfig( | ||||||
|          {path: 'simple', component: SimpleCmp}, |            [{path: 'simple', component: SimpleCmp}, {path: 'blank', component: BlankCmp}]); | ||||||
|          {path: 'blank', component: BlankCmp}, |  | ||||||
|        ]); |  | ||||||
| 
 | 
 | ||||||
|        router.navigateByUrl('/simple'); |        router.navigateByUrl('/simple'); | ||||||
|        advance(fixture); |        advance(fixture); | ||||||
|        expect(fixture.nativeElement).toHaveText('[simple]'); |        expect(location.path()).toEqual('/simple'); | ||||||
| 
 | 
 | ||||||
|        fixture.componentInstance.cond = false; |        const instance = fixture.componentInstance; | ||||||
|  |        instance.cond = false; | ||||||
|        advance(fixture); |        advance(fixture); | ||||||
|        expect(fixture.nativeElement).toHaveText('[]'); |  | ||||||
| 
 | 
 | ||||||
|        fixture.componentInstance.cond = true; |        let recordedError: any = null; | ||||||
|  |        router.navigateByUrl('/blank') !.catch(e => recordedError = e); | ||||||
|        advance(fixture); |        advance(fixture); | ||||||
|        expect(fixture.nativeElement).toHaveText('[simple]'); | 
 | ||||||
|  |        expect(recordedError.message).toEqual('Cannot find primary outlet to load \'BlankCmp\''); | ||||||
|      })); |      })); | ||||||
| 
 | 
 | ||||||
|   it('should update location when navigating', fakeAsync(() => { |   it('should update location when navigating', fakeAsync(() => { | ||||||
| @ -3236,19 +3230,17 @@ describe('Integration', () => { | |||||||
|       shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; } |       shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; } | ||||||
|       store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {} |       store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {} | ||||||
|       shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; } |       shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; } | ||||||
|       retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; } |       retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle { return null !; } | ||||||
|       shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { |       shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { | ||||||
|         if (future.routeConfig !== curr.routeConfig) { |         if (future.routeConfig !== curr.routeConfig) { | ||||||
|           return false; |           return false; | ||||||
|         } |         } else if (Object.keys(future.params).length !== Object.keys(curr.params).length) { | ||||||
| 
 |  | ||||||
|         if (Object.keys(future.params).length !== Object.keys(curr.params).length) { |  | ||||||
|           return false; |           return false; | ||||||
|         } |         } else { | ||||||
| 
 |  | ||||||
|           return Object.keys(future.params).every(k => future.params[k] === curr.params[k]); |           return Object.keys(future.params).every(k => future.params[k] === curr.params[k]); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     it('should support attaching & detaching fragments', |     it('should support attaching & detaching fragments', | ||||||
|        fakeAsync(inject([Router, Location], (router: Router, location: Location) => { |        fakeAsync(inject([Router, Location], (router: Router, location: Location) => { | ||||||
| @ -3257,12 +3249,8 @@ describe('Integration', () => { | |||||||
|          router.routeReuseStrategy = new AttachDetachReuseStrategy(); |          router.routeReuseStrategy = new AttachDetachReuseStrategy(); | ||||||
| 
 | 
 | ||||||
|          router.resetConfig([ |          router.resetConfig([ | ||||||
|            { |            {path: 'a', component: TeamCmp, children: [{path: 'b', component: SimpleCmp}]}, | ||||||
|              path: 'a', |            {path: 'c', component: UserCmp} | ||||||
|              component: TeamCmp, |  | ||||||
|              children: [{path: 'b', component: SimpleCmp}], |  | ||||||
|            }, |  | ||||||
|            {path: 'c', component: UserCmp}, |  | ||||||
|          ]); |          ]); | ||||||
| 
 | 
 | ||||||
|          router.navigateByUrl('/a/b'); |          router.navigateByUrl('/a/b'); | ||||||
| @ -3471,7 +3459,7 @@ class RelativeLinkInIfCmp { | |||||||
| 
 | 
 | ||||||
| @Component( | @Component( | ||||||
|     {selector: 'child', template: '<div *ngIf="alwaysTrue"><router-outlet></router-outlet></div>'}) |     {selector: 'child', template: '<div *ngIf="alwaysTrue"><router-outlet></router-outlet></div>'}) | ||||||
| class OutletInNgIf { | class LinkInNgIf { | ||||||
|   alwaysTrue = true; |   alwaysTrue = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -3550,7 +3538,7 @@ function createRoot(router: Router, type: any): ComponentFixture<any> { | |||||||
|     QueryParamsAndFragmentCmp, |     QueryParamsAndFragmentCmp, | ||||||
|     StringLinkButtonCmp, |     StringLinkButtonCmp, | ||||||
|     WrapperCmp, |     WrapperCmp, | ||||||
|     OutletInNgIf, |     LinkInNgIf, | ||||||
|     ComponentRecordingRoutePathAndUrl, |     ComponentRecordingRoutePathAndUrl, | ||||||
|     RouteCmp, |     RouteCmp, | ||||||
|     RootCmp, |     RootCmp, | ||||||
| @ -3576,7 +3564,7 @@ function createRoot(router: Router, type: any): ComponentFixture<any> { | |||||||
|     QueryParamsAndFragmentCmp, |     QueryParamsAndFragmentCmp, | ||||||
|     StringLinkButtonCmp, |     StringLinkButtonCmp, | ||||||
|     WrapperCmp, |     WrapperCmp, | ||||||
|     OutletInNgIf, |     LinkInNgIf, | ||||||
|     ComponentRecordingRoutePathAndUrl, |     ComponentRecordingRoutePathAndUrl, | ||||||
|     RouteCmp, |     RouteCmp, | ||||||
|     RootCmp, |     RootCmp, | ||||||
| @ -3604,7 +3592,7 @@ function createRoot(router: Router, type: any): ComponentFixture<any> { | |||||||
|     QueryParamsAndFragmentCmp, |     QueryParamsAndFragmentCmp, | ||||||
|     StringLinkButtonCmp, |     StringLinkButtonCmp, | ||||||
|     WrapperCmp, |     WrapperCmp, | ||||||
|     OutletInNgIf, |     LinkInNgIf, | ||||||
|     ComponentRecordingRoutePathAndUrl, |     ComponentRecordingRoutePathAndUrl, | ||||||
|     RouteCmp, |     RouteCmp, | ||||||
|     RootCmp, |     RootCmp, | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ import {TestBed, inject} from '@angular/core/testing'; | |||||||
| 
 | 
 | ||||||
| import {ResolveData} from '../src/config'; | import {ResolveData} from '../src/config'; | ||||||
| import {PreActivation, Router} from '../src/router'; | import {PreActivation, Router} from '../src/router'; | ||||||
| import {ChildrenOutletContexts} from '../src/router_outlet_context'; | import {RouterOutletMap} from '../src/router_outlet_map'; | ||||||
| import {ActivatedRouteSnapshot, RouterStateSnapshot, createEmptyStateSnapshot} from '../src/router_state'; | import {ActivatedRouteSnapshot, RouterStateSnapshot, createEmptyStateSnapshot} from '../src/router_state'; | ||||||
| import {DefaultUrlSerializer} from '../src/url_tree'; | import {DefaultUrlSerializer} from '../src/url_tree'; | ||||||
| import {TreeNode} from '../src/utils/tree'; | import {TreeNode} from '../src/utils/tree'; | ||||||
| @ -109,7 +109,7 @@ describe('Router', () => { | |||||||
| function checkResolveData( | function checkResolveData( | ||||||
|     future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void { |     future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void { | ||||||
|   const p = new PreActivation(future, curr, injector); |   const p = new PreActivation(future, curr, injector); | ||||||
|   p.traverse(new ChildrenOutletContexts()); |   p.traverse(new RouterOutletMap()); | ||||||
|   p.resolveData().subscribe(check, (e) => { throw e; }); |   p.resolveData().subscribe(check, (e) => { throw e; }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
| import {Location, LocationStrategy} from '@angular/common'; | import {Location, LocationStrategy} from '@angular/common'; | ||||||
| import {MockLocationStrategy, SpyLocation} from '@angular/common/testing'; | import {MockLocationStrategy, SpyLocation} from '@angular/common/testing'; | ||||||
| import {Compiler, Injectable, Injector, ModuleWithProviders, NgModule, NgModuleFactory, NgModuleFactoryLoader, Optional} from '@angular/core'; | import {Compiler, Injectable, Injector, ModuleWithProviders, NgModule, NgModuleFactory, NgModuleFactoryLoader, Optional} from '@angular/core'; | ||||||
| import {ChildrenOutletContexts, NoPreloading, PreloadingStrategy, ROUTES, Route, Router, RouterModule, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router'; | import {NoPreloading, PreloadingStrategy, ROUTES, Route, Router, RouterModule, RouterOutletMap, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -82,11 +82,11 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader { | |||||||
|  * @stable |  * @stable | ||||||
|  */ |  */ | ||||||
| export function setupTestingRouter( | export function setupTestingRouter( | ||||||
|     urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location, |     urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, | ||||||
|     loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][], |     loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][], | ||||||
|     urlHandlingStrategy?: UrlHandlingStrategy) { |     urlHandlingStrategy?: UrlHandlingStrategy) { | ||||||
|   const router = new Router( |   const router = new Router( | ||||||
|       null !, urlSerializer, contexts, location, injector, loader, compiler, flatten(routes)); |       null !, urlSerializer, outletMap, location, injector, loader, compiler, flatten(routes)); | ||||||
|   if (urlHandlingStrategy) { |   if (urlHandlingStrategy) { | ||||||
|     router.urlHandlingStrategy = urlHandlingStrategy; |     router.urlHandlingStrategy = urlHandlingStrategy; | ||||||
|   } |   } | ||||||
| @ -127,8 +127,8 @@ export function setupTestingRouter( | |||||||
|       provide: Router, |       provide: Router, | ||||||
|       useFactory: setupTestingRouter, |       useFactory: setupTestingRouter, | ||||||
|       deps: [ |       deps: [ | ||||||
|         UrlSerializer, ChildrenOutletContexts, Location, NgModuleFactoryLoader, Compiler, Injector, |         UrlSerializer, RouterOutletMap, Location, NgModuleFactoryLoader, Compiler, Injector, ROUTES, | ||||||
|         ROUTES, [UrlHandlingStrategy, new Optional()] |         [UrlHandlingStrategy, new Optional()] | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     {provide: PreloadingStrategy, useExisting: NoPreloading}, provideRoutes([]) |     {provide: PreloadingStrategy, useExisting: NoPreloading}, provideRoutes([]) | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								tools/public_api_guard/router/router.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								tools/public_api_guard/router/router.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -59,16 +59,6 @@ export interface CanLoad { | |||||||
|     canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean; |     canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** @stable */ |  | ||||||
| export declare class ChildrenOutletContexts { |  | ||||||
|     getContext(childName: string): OutletContext | null; |  | ||||||
|     getOrCreateContext(childName: string): OutletContext; |  | ||||||
|     onChildOutletCreated(childName: string, outlet: RouterOutlet): void; |  | ||||||
|     onChildOutletDestroyed(childName: string): void; |  | ||||||
|     onOutletDeactivated(): Map<string, OutletContext>; |  | ||||||
|     onOutletReAttached(contexts: Map<string, OutletContext>): void; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** @stable */ | /** @stable */ | ||||||
| export declare function convertToParamMap(params: Params): ParamMap; | export declare function convertToParamMap(params: Params): ParamMap; | ||||||
| 
 | 
 | ||||||
| @ -167,15 +157,6 @@ export declare class NoPreloading implements PreloadingStrategy { | |||||||
|     preload(route: Route, fn: () => Observable<any>): Observable<any>; |     preload(route: Route, fn: () => Observable<any>): Observable<any>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** @stable */ |  | ||||||
| export declare class OutletContext { |  | ||||||
|     attachRef: ComponentRef<any> | null; |  | ||||||
|     children: ChildrenOutletContexts; |  | ||||||
|     outlet: RouterOutlet | null; |  | ||||||
|     resolver: ComponentFactoryResolver | null; |  | ||||||
|     route: ActivatedRoute | null; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** @stable */ | /** @stable */ | ||||||
| export interface ParamMap { | export interface ParamMap { | ||||||
|     readonly keys: string[]; |     readonly keys: string[]; | ||||||
| @ -258,7 +239,7 @@ export declare class Router { | |||||||
|     readonly routerState: RouterState; |     readonly routerState: RouterState; | ||||||
|     readonly url: string; |     readonly url: string; | ||||||
|     urlHandlingStrategy: UrlHandlingStrategy; |     urlHandlingStrategy: UrlHandlingStrategy; | ||||||
|     constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes); |     constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes); | ||||||
|     createUrlTree(commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, preserveFragment}?: NavigationExtras): UrlTree; |     createUrlTree(commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, preserveFragment}?: NavigationExtras): UrlTree; | ||||||
|     dispose(): void; |     dispose(): void; | ||||||
|     initialNavigation(): void; |     initialNavigation(): void; | ||||||
| @ -348,7 +329,7 @@ export declare class RouterModule { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** @stable */ | /** @stable */ | ||||||
| export declare class RouterOutlet implements OnDestroy, OnInit { | export declare class RouterOutlet implements OnDestroy { | ||||||
|     activateEvents: EventEmitter<any>; |     activateEvents: EventEmitter<any>; | ||||||
|     readonly activatedRoute: ActivatedRoute; |     readonly activatedRoute: ActivatedRoute; | ||||||
|     readonly component: Object; |     readonly component: Object; | ||||||
| @ -356,13 +337,20 @@ export declare class RouterOutlet implements OnDestroy, OnInit { | |||||||
|     readonly isActivated: boolean; |     readonly isActivated: boolean; | ||||||
|     /** @deprecated */ readonly locationFactoryResolver: ComponentFactoryResolver; |     /** @deprecated */ readonly locationFactoryResolver: ComponentFactoryResolver; | ||||||
|     /** @deprecated */ readonly locationInjector: Injector; |     /** @deprecated */ readonly locationInjector: Injector; | ||||||
|     constructor(parentContexts: ChildrenOutletContexts, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string); |     outletMap: RouterOutletMap; | ||||||
|     activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void; |     constructor(parentOutletMap: RouterOutletMap, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string); | ||||||
|  |     /** @deprecated */ activate(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver, injector: Injector, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void; | ||||||
|  |     activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null, outletMap: RouterOutletMap): void; | ||||||
|     attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): void; |     attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): void; | ||||||
|     deactivate(): void; |     deactivate(): void; | ||||||
|     detach(): ComponentRef<any>; |     detach(): ComponentRef<any>; | ||||||
|     ngOnDestroy(): void; |     ngOnDestroy(): void; | ||||||
|     ngOnInit(): void; | } | ||||||
|  | 
 | ||||||
|  | /** @stable */ | ||||||
|  | export declare class RouterOutletMap { | ||||||
|  |     registerOutlet(name: string, outlet: RouterOutlet): void; | ||||||
|  |     removeOutlet(name: string): void; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** @stable */ | /** @stable */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user