X Tutup
Skip to content

Commit 2f581ff

Browse files
committed
fix(router): RouterOutlet loads component twice in a race condition
Closes #7497 Closes #7545
1 parent d61aaac commit 2f581ff

File tree

3 files changed

+37
-27
lines changed

3 files changed

+37
-27
lines changed

modules/angular2/src/core/linker/dynamic_component_loader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export abstract class ComponentRef {
5959
*
6060
* TODO(i): rename to destroy to be consistent with AppViewManager and ViewContainerRef
6161
*/
62-
abstract dispose();
62+
abstract dispose(): void;
6363
}
6464

6565
export class ComponentRef_ extends ComponentRef {
@@ -84,7 +84,7 @@ export class ComponentRef_ extends ComponentRef {
8484
*/
8585
get hostComponentType(): Type { return this.componentType; }
8686

87-
dispose() { this._dispose(); }
87+
dispose(): void { this._dispose(); }
8888
}
8989

9090
/**

modules/angular2/src/router/directives/router_outlet.ts

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ let _resolveToTrue = PromiseWrapper.resolve(true);
3434
@Directive({selector: 'router-outlet'})
3535
export class RouterOutlet implements OnDestroy {
3636
name: string = null;
37-
private _componentRef: ComponentRef = null;
37+
private _componentRef: Promise<ComponentRef> = null;
3838
private _currentInstruction: ComponentInstruction = null;
3939

4040
constructor(private _elementRef: ElementRef, private _loader: DynamicComponentLoader,
@@ -62,14 +62,17 @@ export class RouterOutlet implements OnDestroy {
6262
provide(RouteParams, {useValue: new RouteParams(nextInstruction.params)}),
6363
provide(routerMod.Router, {useValue: childRouter})
6464
]);
65-
return this._loader.loadNextToLocation(componentType, this._elementRef, providers)
66-
.then((componentRef) => {
67-
this._componentRef = componentRef;
68-
if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) {
69-
return (<OnActivate>this._componentRef.instance)
70-
.routerOnActivate(nextInstruction, previousInstruction);
71-
}
72-
});
65+
this._componentRef =
66+
this._loader.loadNextToLocation(componentType, this._elementRef, providers);
67+
return this._componentRef.then((componentRef) => {
68+
if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) {
69+
return this._componentRef.then(
70+
(ref: ComponentRef) =>
71+
(<OnActivate>ref.instance).routerOnActivate(nextInstruction, previousInstruction));
72+
} else {
73+
return componentRef;
74+
}
75+
});
7376
}
7477

7578
/**
@@ -86,12 +89,14 @@ export class RouterOutlet implements OnDestroy {
8689
// a new one.
8790
if (isBlank(this._componentRef)) {
8891
return this.activate(nextInstruction);
92+
} else {
93+
return PromiseWrapper.resolve(
94+
hasLifecycleHook(hookMod.routerOnReuse, this._currentInstruction.componentType) ?
95+
this._componentRef.then(
96+
(ref: ComponentRef) =>
97+
(<OnReuse>ref.instance).routerOnReuse(nextInstruction, previousInstruction)) :
98+
true);
8999
}
90-
return PromiseWrapper.resolve(
91-
hasLifecycleHook(hookMod.routerOnReuse, this._currentInstruction.componentType) ?
92-
(<OnReuse>this._componentRef.instance)
93-
.routerOnReuse(nextInstruction, previousInstruction) :
94-
true);
95100
}
96101

97102
/**
@@ -102,14 +107,16 @@ export class RouterOutlet implements OnDestroy {
102107
var next = _resolveToTrue;
103108
if (isPresent(this._componentRef) && isPresent(this._currentInstruction) &&
104109
hasLifecycleHook(hookMod.routerOnDeactivate, this._currentInstruction.componentType)) {
105-
next = <Promise<boolean>>PromiseWrapper.resolve(
106-
(<OnDeactivate>this._componentRef.instance)
107-
.routerOnDeactivate(nextInstruction, this._currentInstruction));
110+
next = this._componentRef.then(
111+
(ref: ComponentRef) =>
112+
(<OnDeactivate>ref.instance)
113+
.routerOnDeactivate(nextInstruction, this._currentInstruction));
108114
}
109115
return next.then((_) => {
110116
if (isPresent(this._componentRef)) {
111-
this._componentRef.dispose();
117+
var onDispose = this._componentRef.then((ref: ComponentRef) => ref.dispose());
112118
this._componentRef = null;
119+
return onDispose;
113120
}
114121
});
115122
}
@@ -127,11 +134,13 @@ export class RouterOutlet implements OnDestroy {
127134
return _resolveToTrue;
128135
}
129136
if (hasLifecycleHook(hookMod.routerCanDeactivate, this._currentInstruction.componentType)) {
130-
return <Promise<boolean>>PromiseWrapper.resolve(
131-
(<CanDeactivate>this._componentRef.instance)
132-
.routerCanDeactivate(nextInstruction, this._currentInstruction));
137+
return this._componentRef.then(
138+
(ref: ComponentRef) =>
139+
(<CanDeactivate>ref.instance)
140+
.routerCanDeactivate(nextInstruction, this._currentInstruction));
141+
} else {
142+
return _resolveToTrue;
133143
}
134-
return _resolveToTrue;
135144
}
136145

137146
/**
@@ -151,8 +160,9 @@ export class RouterOutlet implements OnDestroy {
151160
this._currentInstruction.componentType != nextInstruction.componentType) {
152161
result = false;
153162
} else if (hasLifecycleHook(hookMod.routerCanReuse, this._currentInstruction.componentType)) {
154-
result = (<CanReuse>this._componentRef.instance)
155-
.routerCanReuse(nextInstruction, this._currentInstruction);
163+
result = this._componentRef.then(
164+
(ref: ComponentRef) =>
165+
(<CanReuse>ref.instance).routerCanReuse(nextInstruction, this._currentInstruction));
156166
} else {
157167
result = nextInstruction == this._currentInstruction ||
158168
(isPresent(nextInstruction.params) && isPresent(this._currentInstruction.params) &&

tools/public_api_guard/public_api_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ const CORE = [
106106
'ComponentMetadata.viewProviders:any[]',
107107
'ComponentRef',
108108
'ComponentRef.componentType:Type',
109-
'ComponentRef.dispose():any',
109+
'ComponentRef.dispose():void',
110110
'ComponentRef.hostComponent:any',
111111
'ComponentRef.hostView:HostViewRef',
112112
'ComponentRef.injector:Injector',

0 commit comments

Comments
 (0)
X Tutup