77} from "@angular/core" ;
88import {
99 ActivatedRoute ,
10+ ActivatedRouteSnapshot ,
1011 ChildrenOutletContexts ,
1112 PRIMARY_OUTLET ,
1213} from "@angular/router" ;
@@ -20,7 +21,7 @@ import { BehaviorSubject } from "rxjs/BehaviorSubject";
2021
2122import { isPresent } from "../lang-facade" ;
2223import { DEVICE , PAGE_FACTORY , PageFactory } from "../platform-providers" ;
23- import { routerLog } from "../trace" ;
24+ import { routerLog as log } from "../trace" ;
2425import { DetachedLoader } from "../common/detached-loader" ;
2526import { ViewUtil } from "../view-util" ;
2627import { NSLocationStrategy } from "./ns-location-strategy" ;
@@ -66,7 +67,40 @@ class ChildInjector implements Injector {
6667
6768type ProviderMap = Map < Type < any > | InjectionToken < any > , any > ;
6869
69- const log = ( msg : string ) => routerLog ( msg ) ;
70+ /**
71+ * There are cases where multiple activatedRoute nodes should be associated/handled by the same PageRouterOutlet.
72+ * We can gat additional ActivatedRoutes nodes when there is:
73+ * - Lazy loading - there is an additional ActivatedRoute node for the RouteConfig with the `loadChildren` setup
74+ * - Componentless routes - there is an additional ActivatedRoute node for the componentless RouteConfig
75+ *
76+ * Example:
77+ * R <-- root
78+ * |
79+ * feature (lazy module) <-- RouteConfig: { path: "lazy", loadChildren: "./feature/feature.module#FeatureModule" }
80+ * |
81+ * module (componentless route) <-- RouteConfig: { path: "module", children: [...] } // Note: No 'component'
82+ * |
83+ * home <-- RouteConfig: { path: "module", component: MyComponent } - this is what we get as activatedRoute param
84+ *
85+ * In these cases we will mark the top-most node (feature). NSRouteReuseStrategy will detach the tree there and
86+ * use this ActivateRoute as a kay for caching.
87+ */
88+ export function findTopActivatedRouteNodeForOutlet ( activatedRoute : ActivatedRouteSnapshot ) : ActivatedRouteSnapshot {
89+ let outletActivatedRoute = activatedRoute ;
90+
91+ while ( outletActivatedRoute . parent &&
92+ outletActivatedRoute . parent . routeConfig &&
93+ ! outletActivatedRoute . parent . routeConfig . component ) {
94+
95+ outletActivatedRoute = outletActivatedRoute . parent ;
96+ }
97+
98+ return outletActivatedRoute ;
99+ }
100+
101+ function routeToString ( activatedRoute : ActivatedRoute | ActivatedRouteSnapshot ) : string {
102+ return activatedRoute . pathFromRoot . join ( "->" ) ;
103+ }
70104
71105@Directive ( { selector : "page-router-outlet" } ) // tslint:disable-line:directive-selector
72106export class PageRouterOutlet implements OnDestroy , OnInit { // tslint:disable-line:directive-class-suffix
@@ -181,6 +215,8 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
181215 throw new Error ( "Outlet is not activated" ) ;
182216 }
183217
218+ log ( "PageRouterOutlet.detach() - " + routeToString ( this . _activatedRoute ) ) ;
219+
184220 const component = this . activated ;
185221 this . activated = null ;
186222 this . _activatedRoute = null ;
@@ -191,13 +227,12 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
191227 * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
192228 */
193229 attach ( ref : ComponentRef < any > , activatedRoute : ActivatedRoute ) {
194- log ( "PageRouterOutlet.attach()" +
195- "when RouteReuseStrategy instructs to re-attach " +
196- "previously detached subtree" ) ;
230+ log ( "PageRouterOutlet.attach() - " + routeToString ( activatedRoute ) ) ;
197231
198232 this . activated = ref ;
199233 this . _activatedRoute = activatedRoute ;
200- this . _activatedRoute . snapshot [ pageRouterActivatedSymbol ] = true ;
234+
235+ this . markActivatedRoute ( activatedRoute ) ;
201236
202237 this . locationStrategy . _finishBackPageNavigation ( ) ;
203238 }
@@ -215,10 +250,11 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
215250 throw new Error ( "Currently in page back navigation - component should be reattached instead of activated." ) ;
216251 }
217252
218- log ( "PageRouterOutlet.activateWith() - instantiating new component" ) ;
253+ log ( "PageRouterOutlet.activateWith() - " + routeToString ( activatedRoute ) ) ;
219254
220255 this . _activatedRoute = activatedRoute ;
221- this . _activatedRoute . snapshot [ pageRouterActivatedSymbol ] = true ;
256+
257+ this . markActivatedRoute ( activatedRoute ) ;
222258
223259 resolver = resolver || this . resolver ;
224260
@@ -318,6 +354,12 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
318354 } ) ;
319355 }
320356
357+ private markActivatedRoute ( activatedRoute : ActivatedRoute ) {
358+ const nodeToMark = findTopActivatedRouteNodeForOutlet ( activatedRoute . snapshot ) ;
359+ nodeToMark [ pageRouterActivatedSymbol ] = true ;
360+ log ( "Activated route marked as page: " + routeToString ( nodeToMark ) ) ;
361+ }
362+
321363 // NOTE: Using private APIs - potential break point!
322364 private getComponentFactory (
323365 activatedRoute : any ,
0 commit comments