7
7
} from "@angular/core" ;
8
8
import {
9
9
ActivatedRoute ,
10
+ ActivatedRouteSnapshot ,
10
11
ChildrenOutletContexts ,
11
12
PRIMARY_OUTLET ,
12
13
} from "@angular/router" ;
@@ -20,7 +21,7 @@ import { BehaviorSubject } from "rxjs/BehaviorSubject";
20
21
21
22
import { isPresent } from "../lang-facade" ;
22
23
import { DEVICE , PAGE_FACTORY , PageFactory } from "../platform-providers" ;
23
- import { routerLog } from "../trace" ;
24
+ import { routerLog as log } from "../trace" ;
24
25
import { DetachedLoader } from "../common/detached-loader" ;
25
26
import { ViewUtil } from "../view-util" ;
26
27
import { NSLocationStrategy } from "./ns-location-strategy" ;
@@ -66,7 +67,40 @@ class ChildInjector implements Injector {
66
67
67
68
type ProviderMap = Map < Type < any > | InjectionToken < any > , any > ;
68
69
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
+ }
70
104
71
105
@Directive ( { selector : "page-router-outlet" } ) // tslint:disable-line:directive-selector
72
106
export class PageRouterOutlet implements OnDestroy , OnInit { // tslint:disable-line:directive-class-suffix
@@ -181,6 +215,8 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
181
215
throw new Error ( "Outlet is not activated" ) ;
182
216
}
183
217
218
+ log ( "PageRouterOutlet.detach() - " + routeToString ( this . _activatedRoute ) ) ;
219
+
184
220
const component = this . activated ;
185
221
this . activated = null ;
186
222
this . _activatedRoute = null ;
@@ -191,13 +227,12 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
191
227
* Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
192
228
*/
193
229
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 ) ) ;
197
231
198
232
this . activated = ref ;
199
233
this . _activatedRoute = activatedRoute ;
200
- this . _activatedRoute . snapshot [ pageRouterActivatedSymbol ] = true ;
234
+
235
+ this . markActivatedRoute ( activatedRoute ) ;
201
236
202
237
this . locationStrategy . _finishBackPageNavigation ( ) ;
203
238
}
@@ -215,10 +250,11 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
215
250
throw new Error ( "Currently in page back navigation - component should be reattached instead of activated." ) ;
216
251
}
217
252
218
- log ( "PageRouterOutlet.activateWith() - instantiating new component" ) ;
253
+ log ( "PageRouterOutlet.activateWith() - " + routeToString ( activatedRoute ) ) ;
219
254
220
255
this . _activatedRoute = activatedRoute ;
221
- this . _activatedRoute . snapshot [ pageRouterActivatedSymbol ] = true ;
256
+
257
+ this . markActivatedRoute ( activatedRoute ) ;
222
258
223
259
resolver = resolver || this . resolver ;
224
260
@@ -318,6 +354,12 @@ export class PageRouterOutlet implements OnDestroy, OnInit { // tslint:disable-l
318
354
} ) ;
319
355
}
320
356
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
+
321
363
// NOTE: Using private APIs - potential break point!
322
364
private getComponentFactory (
323
365
activatedRoute : any ,
0 commit comments