|
6 | 6 | * found in the LICENSE file at https://angular.io/license |
7 | 7 | */ |
8 | 8 |
|
9 | | -import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core'; |
10 | | -import {RouterOutletMap} from '../router_outlet_map'; |
| 9 | +import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef} from '@angular/core'; |
| 10 | +import {ChildrenOutletContexts} from '../router_outlet_context'; |
11 | 11 | import {ActivatedRoute} from '../router_state'; |
12 | 12 | import {PRIMARY_OUTLET} from '../shared'; |
13 | 13 |
|
@@ -36,23 +36,39 @@ import {PRIMARY_OUTLET} from '../shared'; |
36 | 36 | * @stable |
37 | 37 | */ |
38 | 38 | @Directive({selector: 'router-outlet'}) |
39 | | -export class RouterOutlet implements OnDestroy { |
| 39 | +export class RouterOutlet implements OnDestroy, OnInit { |
40 | 40 | private activated: ComponentRef<any>|null = null; |
41 | 41 | private _activatedRoute: ActivatedRoute|null = null; |
42 | | - private _outletName: string; |
43 | | - public outletMap: RouterOutletMap; |
| 42 | + private name: string; |
44 | 43 |
|
45 | 44 | @Output('activate') activateEvents = new EventEmitter<any>(); |
46 | 45 | @Output('deactivate') deactivateEvents = new EventEmitter<any>(); |
47 | 46 |
|
48 | 47 | constructor( |
49 | | - private parentOutletMap: RouterOutletMap, private location: ViewContainerRef, |
| 48 | + private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef, |
50 | 49 | private resolver: ComponentFactoryResolver, @Attribute('name') name: string) { |
51 | | - this._outletName = name || PRIMARY_OUTLET; |
52 | | - parentOutletMap.registerOutlet(this._outletName, this); |
| 50 | + this.name = name || PRIMARY_OUTLET; |
| 51 | + parentContexts.onChildOutletCreated(this.name, this); |
53 | 52 | } |
54 | 53 |
|
55 | | - ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this._outletName); } |
| 54 | + ngOnDestroy(): void { this.parentContexts.onChildOutletDestroyed(this.name); } |
| 55 | + |
| 56 | + ngOnInit(): void { |
| 57 | + if (!this.activated) { |
| 58 | + // If the outlet was not instantiated at the time the route got activated we need to populate |
| 59 | + // the outlet when it is initialized. |
| 60 | + const context = this.parentContexts.getContext(this.name); |
| 61 | + if (context && context.route) { |
| 62 | + if (context.attachRef) { |
| 63 | + // `attachRef` is populated when there is an existing component to mount |
| 64 | + this.attach(context.attachRef, context.route); |
| 65 | + } else { |
| 66 | + // otherwise the component defined in the configuration is created |
| 67 | + this.activateWith(context.route, context.resolver || null); |
| 68 | + } |
| 69 | + } |
| 70 | + } |
| 71 | + } |
56 | 72 |
|
57 | 73 | /** @deprecated since v4 **/ |
58 | 74 | get locationInjector(): Injector { return this.location.injector; } |
@@ -102,65 +118,34 @@ export class RouterOutlet implements OnDestroy { |
102 | 118 | } |
103 | 119 | } |
104 | 120 |
|
105 | | - /** @deprecated since v4, use {@link #activateWith} */ |
106 | | - activate( |
107 | | - activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver, injector: Injector, |
108 | | - providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void { |
| 121 | + activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) { |
109 | 122 | if (this.isActivated) { |
110 | 123 | throw new Error('Cannot activate an already activated outlet'); |
111 | 124 | } |
112 | | - |
113 | | - this.outletMap = outletMap; |
114 | 125 | this._activatedRoute = activatedRoute; |
115 | | - |
116 | | - const snapshot = activatedRoute._futureSnapshot; |
117 | | - const component: any = <any>snapshot._routeConfig !.component; |
118 | | - const factory = resolver.resolveComponentFactory(component) !; |
119 | | - |
120 | | - const inj = ReflectiveInjector.fromResolvedProviders(providers, injector); |
121 | | - |
122 | | - this.activated = this.location.createComponent(factory, this.location.length, inj, []); |
123 | | - this.activated.changeDetectorRef.detectChanges(); |
124 | | - |
125 | | - this.activateEvents.emit(this.activated.instance); |
126 | | - } |
127 | | - |
128 | | - activateWith( |
129 | | - activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null, |
130 | | - outletMap: RouterOutletMap) { |
131 | | - if (this.isActivated) { |
132 | | - throw new Error('Cannot activate an already activated outlet'); |
133 | | - } |
134 | | - |
135 | | - this.outletMap = outletMap; |
136 | | - this._activatedRoute = activatedRoute; |
137 | | - |
138 | 126 | const snapshot = activatedRoute._futureSnapshot; |
139 | 127 | const component = <any>snapshot._routeConfig !.component; |
140 | | - |
141 | 128 | resolver = resolver || this.resolver; |
142 | 129 | const factory = resolver.resolveComponentFactory(component); |
143 | | - |
144 | | - const injector = new OutletInjector(activatedRoute, outletMap, this.location.injector); |
145 | | - |
| 130 | + const childContexts = this.parentContexts.getOrCreateContext(this.name).children; |
| 131 | + const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector); |
146 | 132 | this.activated = this.location.createComponent(factory, this.location.length, injector); |
147 | | - this.activated.changeDetectorRef.detectChanges(); |
148 | | - |
149 | 133 | this.activateEvents.emit(this.activated.instance); |
150 | 134 | } |
151 | 135 | } |
152 | 136 |
|
153 | 137 | class OutletInjector implements Injector { |
154 | 138 | constructor( |
155 | | - private route: ActivatedRoute, private map: RouterOutletMap, private parent: Injector) {} |
| 139 | + private route: ActivatedRoute, private childContexts: ChildrenOutletContexts, |
| 140 | + private parent: Injector) {} |
156 | 141 |
|
157 | 142 | get(token: any, notFoundValue?: any): any { |
158 | 143 | if (token === ActivatedRoute) { |
159 | 144 | return this.route; |
160 | 145 | } |
161 | 146 |
|
162 | | - if (token === RouterOutletMap) { |
163 | | - return this.map; |
| 147 | + if (token === ChildrenOutletContexts) { |
| 148 | + return this.childContexts; |
164 | 149 | } |
165 | 150 |
|
166 | 151 | return this.parent.get(token, notFoundValue); |
|
0 commit comments