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