fix(router): support outlets within dynamic components
Fixes internal b/27294172
This commit is contained in:

committed by
Vikram Subramanian

parent
75343eb340
commit
7d44b8230e
@ -1,7 +1,6 @@
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
|
||||
import {
|
||||
Directive,
|
||||
@ -11,7 +10,8 @@ import {
|
||||
ElementRef,
|
||||
Injector,
|
||||
provide,
|
||||
Dependency
|
||||
Dependency,
|
||||
OnDestroy
|
||||
} from 'angular2/core';
|
||||
|
||||
import * as routerMod from '../router';
|
||||
@ -32,7 +32,7 @@ let _resolveToTrue = PromiseWrapper.resolve(true);
|
||||
* ```
|
||||
*/
|
||||
@Directive({selector: 'router-outlet'})
|
||||
export class RouterOutlet {
|
||||
export class RouterOutlet implements OnDestroy {
|
||||
name: string = null;
|
||||
private _componentRef: ComponentRef = null;
|
||||
private _currentInstruction: ComponentInstruction = null;
|
||||
@ -81,8 +81,11 @@ export class RouterOutlet {
|
||||
var previousInstruction = this._currentInstruction;
|
||||
this._currentInstruction = nextInstruction;
|
||||
|
||||
// it's possible the component is removed before it can be reactivated (if nested withing
|
||||
// another dynamically loaded component, for instance). In that case, we simply activate
|
||||
// a new one.
|
||||
if (isBlank(this._componentRef)) {
|
||||
throw new BaseException(`Cannot reuse an outlet that does not contain a component.`);
|
||||
return this.activate(nextInstruction);
|
||||
}
|
||||
return PromiseWrapper.resolve(
|
||||
hasLifecycleHook(hookMod.routerOnReuse, this._currentInstruction.componentType) ?
|
||||
@ -157,4 +160,6 @@ export class RouterOutlet {
|
||||
}
|
||||
return PromiseWrapper.resolve(result);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void { this._parentRouter.unregisterPrimaryOutlet(this); }
|
||||
}
|
||||
|
@ -78,6 +78,10 @@ export class Router {
|
||||
throw new BaseException(`registerPrimaryOutlet expects to be called with an unnamed outlet.`);
|
||||
}
|
||||
|
||||
if (isPresent(this._outlet)) {
|
||||
throw new BaseException(`Primary outlet is already registered.`);
|
||||
}
|
||||
|
||||
this._outlet = outlet;
|
||||
if (isPresent(this._currentInstruction)) {
|
||||
return this.commit(this._currentInstruction, false);
|
||||
@ -85,6 +89,19 @@ export class Router {
|
||||
return _resolveToTrue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an outlet (because it was destroyed, etc).
|
||||
*
|
||||
* You probably don't need to use this unless you're writing a custom outlet implementation.
|
||||
*/
|
||||
unregisterPrimaryOutlet(outlet: RouterOutlet): void {
|
||||
if (isPresent(outlet.name)) {
|
||||
throw new BaseException(`registerPrimaryOutlet expects to be called with an unnamed outlet.`);
|
||||
}
|
||||
this._outlet = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register an outlet to notified of auxiliary route changes.
|
||||
*
|
||||
@ -198,6 +215,26 @@ export class Router {
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_settleInstruction(instruction: Instruction): Promise<any> {
|
||||
return instruction.resolveComponent().then((_) => {
|
||||
var unsettledInstructions: Array<Promise<any>> = [];
|
||||
|
||||
if (isPresent(instruction.component)) {
|
||||
instruction.component.reuse = false;
|
||||
}
|
||||
|
||||
if (isPresent(instruction.child)) {
|
||||
unsettledInstructions.push(this._settleInstruction(instruction.child));
|
||||
}
|
||||
|
||||
StringMapWrapper.forEach(instruction.auxInstruction, (instruction, _) => {
|
||||
unsettledInstructions.push(this._settleInstruction(instruction));
|
||||
});
|
||||
return PromiseWrapper.all(unsettledInstructions);
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_navigate(instruction: Instruction, _skipLocationChange: boolean): Promise<any> {
|
||||
return this._settleInstruction(instruction)
|
||||
@ -220,26 +257,6 @@ export class Router {
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_settleInstruction(instruction: Instruction): Promise<any> {
|
||||
return instruction.resolveComponent().then((_) => {
|
||||
var unsettledInstructions: Array<Promise<any>> = [];
|
||||
|
||||
if (isPresent(instruction.component)) {
|
||||
instruction.component.reuse = false;
|
||||
}
|
||||
|
||||
if (isPresent(instruction.child)) {
|
||||
unsettledInstructions.push(this._settleInstruction(instruction.child));
|
||||
}
|
||||
|
||||
StringMapWrapper.forEach(instruction.auxInstruction, (instruction, _) => {
|
||||
unsettledInstructions.push(this._settleInstruction(instruction));
|
||||
});
|
||||
return PromiseWrapper.all(unsettledInstructions);
|
||||
});
|
||||
}
|
||||
|
||||
private _emitNavigationFinish(url): void { ObservableWrapper.callEmit(this._subject, url); }
|
||||
|
||||
private _afterPromiseFinishNavigating(promise: Promise<any>): Promise<any> {
|
||||
|
Reference in New Issue
Block a user