feat(router): implement Router.isRouteActive

This commit is contained in:
Brian Ford 2015-08-30 21:25:46 -07:00
parent e1a7e0329c
commit de37729823
5 changed files with 241 additions and 192 deletions

View File

@ -132,62 +132,41 @@ function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $
} }
} }
router.registerOutlet({ router.registerPrimaryOutlet({
commit: function (instruction) { reuse: function (instruction) {
var next = $q.when(true); var next = $q.when(true);
var componentInstruction = instruction.component;
if (componentInstruction.reuse) {
var previousInstruction = currentInstruction; var previousInstruction = currentInstruction;
currentInstruction = componentInstruction; currentInstruction = instruction;
if (currentController.onReuse) { if (currentController.onReuse) {
next = $q.when(currentController.onReuse(currentInstruction, previousInstruction)); next = $q.when(currentController.onReuse(currentInstruction, previousInstruction));
} }
} else {
var self = this; return next;
next = this.deactivate(instruction).then(function () {
return self.activate(componentInstruction);
});
}
return next.then(function () {
if (childRouter) {
return childRouter.commit(instruction.child);
} else {
return $q.when(true);
}
});
}, },
canReuse: function (nextInstruction) { canReuse: function (nextInstruction) {
var result; var result;
var componentInstruction = nextInstruction.component;
if (!currentInstruction || if (!currentInstruction ||
currentInstruction.componentType !== componentInstruction.componentType) { currentInstruction.componentType !== nextInstruction.componentType) {
result = false; result = false;
} else if (currentController.canReuse) { } else if (currentController.canReuse) {
result = currentController.canReuse(componentInstruction, currentInstruction); result = currentController.canReuse(nextInstruction, currentInstruction);
} else { } else {
result = componentInstruction === currentInstruction || result = nextInstruction === currentInstruction ||
angular.equals(componentInstruction.params, currentInstruction.params); angular.equals(nextInstruction.params, currentInstruction.params);
} }
return $q.when(result).then(function (result) { return $q.when(result);
// TODO: this is a hack
componentInstruction.reuse = result;
return result;
});
}, },
canDeactivate: function (instruction) { canDeactivate: function (instruction) {
if (currentInstruction && currentController && currentController.canDeactivate) { if (currentInstruction && currentController && currentController.canDeactivate) {
return $q.when(currentController.canDeactivate(instruction && instruction.component, currentInstruction)); return $q.when(currentController.canDeactivate(instruction, currentInstruction));
} }
return $q.when(true); return $q.when(true);
}, },
deactivate: function (instruction) { deactivate: function (instruction) {
// todo(shahata): childRouter.dectivate, dispose component?
var result = $q.when();
return result.then(function () {
if (currentController && currentController.onDeactivate) { if (currentController && currentController.onDeactivate) {
return currentController.onDeactivate(instruction && instruction.component, currentInstruction); return $q.when(currentController.onDeactivate(instruction, currentInstruction));
} }
}); return $q.when();
}, },
activate: function (instruction) { activate: function (instruction) {
var previousInstruction = currentInstruction; var previousInstruction = currentInstruction;
@ -228,7 +207,7 @@ function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $
} }
}); });
} }
}, outletName); });
} }
} }

View File

@ -54,11 +54,16 @@ export class Router {
lastNavigationAttempt: string; lastNavigationAttempt: string;
private _currentInstruction: Instruction = null; private _currentInstruction: Instruction = null;
private _currentNavigation: Promise<any> = _resolveToTrue; private _currentNavigation: Promise<any> = _resolveToTrue;
private _outlet: RouterOutlet = null; private _outlet: RouterOutlet = null;
private _auxOutlets: Map<string, RouterOutlet> = new Map();
private _auxRouters: Map<string, Router> = new Map();
private _childRouter: Router;
private _subject: EventEmitter = new EventEmitter(); private _subject: EventEmitter = new EventEmitter();
constructor(public registry: RouteRegistry, public _pipeline: Pipeline, public parent: Router, constructor(public registry: RouteRegistry, public _pipeline: Pipeline, public parent: Router,
public hostComponent: any) {} public hostComponent: any) {}
@ -67,25 +72,74 @@ export class Router {
* Constructs a child router. You probably don't need to use this unless you're writing a reusable * Constructs a child router. You probably don't need to use this unless you're writing a reusable
* component. * component.
*/ */
childRouter(hostComponent: any): Router { return new ChildRouter(this, hostComponent); } childRouter(hostComponent: any): Router {
return this._childRouter = new ChildRouter(this, hostComponent);
}
/** /**
* Register an object to notify of route changes. You probably don't need to use this unless * Constructs a child router. You probably don't need to use this unless you're writing a reusable
* you're writing a reusable component. * component.
*/ */
registerOutlet(outlet: RouterOutlet): Promise<boolean> { auxRouter(hostComponent: any): Router { return new ChildRouter(this, hostComponent); }
/**
* Register an outlet to notified of primary route changes.
*
* You probably don't need to use this unless you're writing a reusable component.
*/
registerPrimaryOutlet(outlet: RouterOutlet): Promise<boolean> {
if (isPresent(outlet.name)) { if (isPresent(outlet.name)) {
this._auxOutlets.set(outlet.name, outlet); throw new BaseException(`registerAuxOutlet expects to be called with an unnamed outlet.`);
} else {
this._outlet = outlet;
} }
this._outlet = outlet;
if (isPresent(this._currentInstruction)) { if (isPresent(this._currentInstruction)) {
return outlet.commit(this._currentInstruction); return this.commit(this._currentInstruction, false);
} }
return _resolveToTrue; return _resolveToTrue;
} }
/**
* Register an outlet to notified of auxiliary route changes.
*
* You probably don't need to use this unless you're writing a reusable component.
*/
registerAuxOutlet(outlet: RouterOutlet): Promise<boolean> {
var outletName = outlet.name;
if (isBlank(outletName)) {
throw new BaseException(`registerAuxOutlet expects to be called with an outlet with a name.`);
}
// TODO...
// what is the host of an aux route???
var router = this.auxRouter(this.hostComponent);
this._auxRouters.set(outletName, router);
router._outlet = outlet;
var auxInstruction;
if (isPresent(this._currentInstruction) &&
isPresent(auxInstruction = this._currentInstruction.auxInstruction[outletName])) {
return router.commit(auxInstruction);
}
return _resolveToTrue;
}
/**
* Given an instruction, returns `true` if the instruction is currently active,
* otherwise `false`.
*/
isRouteActive(instruction: Instruction): boolean {
var router = this;
while (isPresent(router.parent) && isPresent(instruction.child)) {
router = router.parent;
instruction = instruction.child;
}
return isPresent(this._currentInstruction) &&
this._currentInstruction.component == instruction.component;
}
/** /**
* Dynamically update the routing configuration and trigger a navigation. * Dynamically update the routing configuration and trigger a navigation.
@ -143,7 +197,7 @@ export class Router {
_navigate(instruction: Instruction, _skipLocationChange: boolean): Promise<any> { _navigate(instruction: Instruction, _skipLocationChange: boolean): Promise<any> {
return this._settleInstruction(instruction) return this._settleInstruction(instruction)
.then((_) => this._reuse(instruction)) .then((_) => this._canReuse(instruction))
.then((_) => this._canActivate(instruction)) .then((_) => this._canActivate(instruction))
.then((result) => { .then((result) => {
if (!result) { if (!result) {
@ -190,14 +244,17 @@ export class Router {
}); });
} }
_reuse(instruction: Instruction): Promise<any> { /*
* Recursively set reuse flags
*/
_canReuse(instruction: Instruction): Promise<any> {
if (isBlank(this._outlet)) { if (isBlank(this._outlet)) {
return _resolveToFalse; return _resolveToFalse;
} }
return this._outlet.canReuse(instruction) return this._outlet.canReuse(instruction.component)
.then((result) => { .then((result) => {
if (isPresent(this._outlet.childRouter) && isPresent(instruction.child)) { if (isPresent(this._childRouter) && isPresent(instruction.child)) {
return this._outlet.childRouter._reuse(instruction.child); return this._childRouter._canReuse(instruction.child);
} }
}); });
} }
@ -211,19 +268,26 @@ export class Router {
return _resolveToTrue; return _resolveToTrue;
} }
var next: Promise<boolean>; var next: Promise<boolean>;
if (isPresent(instruction) && instruction.component.reuse) { var childInstruction: Instruction = null;
var reuse: boolean = false;
var componentInstruction: ComponentInstruction = null;
if (isPresent(instruction)) {
childInstruction = instruction.child;
componentInstruction = instruction.component;
reuse = instruction.component.reuse;
}
if (reuse) {
next = _resolveToTrue; next = _resolveToTrue;
} else { } else {
next = this._outlet.canDeactivate(instruction); next = this._outlet.canDeactivate(componentInstruction);
} }
// TODO: aux route lifecycle hooks // TODO: aux route lifecycle hooks
return next.then((result) => { return next.then((result) => {
if (result == false) { if (result == false) {
return false; return false;
} }
if (isPresent(this._outlet.childRouter)) { if (isPresent(this._childRouter)) {
return this._outlet.childRouter._canDeactivate(isPresent(instruction) ? instruction.child : return this._childRouter._canDeactivate(childInstruction);
null);
} }
return true; return true;
}); });
@ -234,13 +298,29 @@ export class Router {
*/ */
commit(instruction: Instruction, _skipLocationChange: boolean = false): Promise<any> { commit(instruction: Instruction, _skipLocationChange: boolean = false): Promise<any> {
this._currentInstruction = instruction; this._currentInstruction = instruction;
var next = _resolveToTrue; var next: Promise<any> = _resolveToTrue;
if (isPresent(this._outlet)) { if (isPresent(this._outlet)) {
next = this._outlet.commit(instruction); var componentInstruction = instruction.component;
if (componentInstruction.reuse) {
next = this._outlet.reuse(componentInstruction);
} else {
next =
this.deactivate(instruction).then((_) => this._outlet.activate(componentInstruction));
} }
if (isPresent(instruction.child)) {
next = next.then((_) => {
if (isPresent(this._childRouter)) {
return this._childRouter.commit(instruction.child);
}
});
}
}
var promises = []; var promises = [];
MapWrapper.forEach(this._auxOutlets, MapWrapper.forEach(this._auxRouters, (router, name) => {
(outlet, _) => { promises.push(outlet.commit(instruction)); }); promises.push(router.commit(instruction.auxInstruction[name]));
});
return next.then((_) => PromiseWrapper.all(promises)); return next.then((_) => PromiseWrapper.all(promises));
} }
@ -262,10 +342,23 @@ export class Router {
* Removes the contents of this router's outlet and all descendant outlets * Removes the contents of this router's outlet and all descendant outlets
*/ */
deactivate(instruction: Instruction): Promise<any> { deactivate(instruction: Instruction): Promise<any> {
if (isPresent(this._outlet)) { var childInstruction: Instruction = null;
return this._outlet.deactivate(instruction); var componentInstruction: ComponentInstruction = null;
if (isPresent(instruction)) {
childInstruction = instruction.child;
componentInstruction = instruction.component;
} }
return _resolveToTrue; var next: Promise<any> = _resolveToTrue;
if (isPresent(this._childRouter)) {
next = this._childRouter.deactivate(childInstruction);
}
if (isPresent(this._outlet)) {
next = next.then((_) => this._outlet.deactivate(componentInstruction));
}
// TODO: handle aux routes
return next;
} }

View File

@ -1,17 +1,19 @@
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async'; import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
import {StringMapWrapper} from 'angular2/src/core/facade/collection'; import {StringMapWrapper} from 'angular2/src/core/facade/collection';
import {isBlank, isPresent} from 'angular2/src/core/facade/lang'; import {isBlank, isPresent, BaseException} from 'angular2/src/core/facade/lang';
import {Directive, Attribute} from '../core/metadata'; import {Directive, Attribute} from '../core/metadata';
import {DynamicComponentLoader, ComponentRef, ElementRef} from 'angular2/core'; import {DynamicComponentLoader, ComponentRef, ElementRef} from 'angular2/core';
import {Injector, bind, Dependency, UNDEFINED} from 'angular2/di'; import {Injector, bind, Dependency, UNDEFINED} from 'angular2/di';
import * as routerMod from './router'; import * as routerMod from './router';
import {Instruction, ComponentInstruction, RouteParams} from './instruction'; import {ComponentInstruction, RouteParams} from './instruction';
import {ROUTE_DATA} from './route_data'; import {ROUTE_DATA} from './route_data';
import * as hookMod from './lifecycle_annotations'; import * as hookMod from './lifecycle_annotations';
import {hasLifecycleHook} from './route_lifecycle_reflector'; import {hasLifecycleHook} from './route_lifecycle_reflector';
let _resolveToTrue = PromiseWrapper.resolve(true);
/** /**
* A router outlet is a placeholder that Angular dynamically fills based on the application's route. * A router outlet is a placeholder that Angular dynamically fills based on the application's route.
* *
@ -23,7 +25,6 @@ import {hasLifecycleHook} from './route_lifecycle_reflector';
*/ */
@Directive({selector: 'router-outlet'}) @Directive({selector: 'router-outlet'})
export class RouterOutlet { export class RouterOutlet {
childRouter: routerMod.Router = null;
name: string = null; name: string = null;
private _componentRef: ComponentRef = null; private _componentRef: ComponentRef = null;
@ -33,141 +34,96 @@ export class RouterOutlet {
private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) { private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) {
if (isPresent(nameAttr)) { if (isPresent(nameAttr)) {
this.name = nameAttr; this.name = nameAttr;
} this._parentRouter.registerAuxOutlet(this);
this._parentRouter.registerOutlet(this);
}
/**
* Given an instruction, update the contents of this outlet.
*/
commit(instruction: Instruction): Promise<any> {
instruction = this._getInstruction(instruction);
var componentInstruction = instruction.component;
if (isBlank(componentInstruction)) {
return PromiseWrapper.resolve(true);
}
var next;
if (componentInstruction.reuse) {
next = this._reuse(componentInstruction);
} else { } else {
next = this.deactivate(instruction).then((_) => this._activate(componentInstruction)); this._parentRouter.registerPrimaryOutlet(this);
}
return next.then((_) => this._commitChild(instruction));
}
private _getInstruction(instruction: Instruction): Instruction {
if (isPresent(this.name)) {
return instruction.auxInstruction[this.name];
} else {
return instruction;
} }
} }
private _commitChild(instruction: Instruction): Promise<any> { activate(nextInstruction: ComponentInstruction): Promise<any> {
if (isPresent(this.childRouter)) {
return this.childRouter.commit(instruction.child);
} else {
return PromiseWrapper.resolve(true);
}
}
private _activate(instruction: ComponentInstruction): Promise<any> {
var previousInstruction = this._currentInstruction; var previousInstruction = this._currentInstruction;
this._currentInstruction = instruction; this._currentInstruction = nextInstruction;
var componentType = instruction.componentType; var componentType = nextInstruction.componentType;
this.childRouter = this._parentRouter.childRouter(componentType); var childRouter = this._parentRouter.childRouter(componentType);
var bindings = Injector.resolve([ var bindings = Injector.resolve([
bind(ROUTE_DATA) bind(ROUTE_DATA)
.toValue(instruction.routeData()), .toValue(nextInstruction.routeData()),
bind(RouteParams).toValue(new RouteParams(instruction.params)), bind(RouteParams).toValue(new RouteParams(nextInstruction.params)),
bind(routerMod.Router).toValue(this.childRouter) bind(routerMod.Router).toValue(childRouter)
]); ]);
return this._loader.loadNextToLocation(componentType, this._elementRef, bindings) return this._loader.loadNextToLocation(componentType, this._elementRef, bindings)
.then((componentRef) => { .then((componentRef) => {
this._componentRef = componentRef; this._componentRef = componentRef;
if (hasLifecycleHook(hookMod.onActivate, componentType)) { if (hasLifecycleHook(hookMod.onActivate, componentType)) {
return this._componentRef.instance.onActivate(instruction, previousInstruction); return this._componentRef.instance.onActivate(nextInstruction, previousInstruction);
} }
}); });
} }
reuse(nextInstruction: ComponentInstruction): Promise<any> {
/**
* Called by Router during recognition phase
*/
canDeactivate(nextInstruction: Instruction): Promise<boolean> {
if (isBlank(this._currentInstruction)) {
return PromiseWrapper.resolve(true);
}
var outletInstruction = this._getInstruction(nextInstruction);
if (hasLifecycleHook(hookMod.canDeactivate, this._currentInstruction.componentType)) {
return PromiseWrapper.resolve(this._componentRef.instance.canDeactivate(
isPresent(outletInstruction) ? outletInstruction.component : null,
this._currentInstruction));
}
return PromiseWrapper.resolve(true);
}
/**
* Called by Router during recognition phase
*/
canReuse(nextInstruction: Instruction): Promise<boolean> {
var result;
var outletInstruction = this._getInstruction(nextInstruction);
var componentInstruction = outletInstruction.component;
if (isBlank(this._currentInstruction) ||
this._currentInstruction.componentType != componentInstruction.componentType) {
result = false;
} else if (hasLifecycleHook(hookMod.canReuse, this._currentInstruction.componentType)) {
result = this._componentRef.instance.canReuse(componentInstruction, this._currentInstruction);
} else {
result =
componentInstruction == this._currentInstruction ||
(isPresent(componentInstruction.params) && isPresent(this._currentInstruction.params) &&
StringMapWrapper.equals(componentInstruction.params, this._currentInstruction.params));
}
return PromiseWrapper.resolve(result).then((result) => {
// TODO: this is a hack
componentInstruction.reuse = result;
return result;
});
}
private _reuse(instruction: ComponentInstruction): Promise<any> {
var previousInstruction = this._currentInstruction; var previousInstruction = this._currentInstruction;
this._currentInstruction = instruction; this._currentInstruction = nextInstruction;
if (isBlank(this._componentRef)) {
throw new BaseException(`Cannot reuse an outlet that does not contain a component.`);
}
return PromiseWrapper.resolve( return PromiseWrapper.resolve(
hasLifecycleHook(hookMod.onReuse, this._currentInstruction.componentType) ? hasLifecycleHook(hookMod.onReuse, this._currentInstruction.componentType) ?
this._componentRef.instance.onReuse(instruction, previousInstruction) : this._componentRef.instance.onReuse(nextInstruction, previousInstruction) :
true); true);
} }
deactivate(nextInstruction: ComponentInstruction): Promise<any> {
var next = _resolveToTrue;
deactivate(nextInstruction: Instruction): Promise<any> {
var outletInstruction = this._getInstruction(nextInstruction);
var componentInstruction = isPresent(outletInstruction) ? outletInstruction.component : null;
return (isPresent(this.childRouter) ?
this.childRouter.deactivate(isPresent(outletInstruction) ? outletInstruction.child :
null) :
PromiseWrapper.resolve(true))
.then((_) => {
if (isPresent(this._componentRef) && isPresent(this._currentInstruction) && if (isPresent(this._componentRef) && isPresent(this._currentInstruction) &&
hasLifecycleHook(hookMod.onDeactivate, this._currentInstruction.componentType)) { hasLifecycleHook(hookMod.onDeactivate, this._currentInstruction.componentType)) {
return this._componentRef.instance.onDeactivate(componentInstruction, next = PromiseWrapper.resolve(
this._currentInstruction); this._componentRef.instance.onDeactivate(nextInstruction, this._currentInstruction));
} }
}) return next.then((_) => {
.then((_) => {
if (isPresent(this._componentRef)) { if (isPresent(this._componentRef)) {
this._componentRef.dispose(); this._componentRef.dispose();
this._componentRef = null; this._componentRef = null;
} }
}); });
} }
/**
* Called by Router during recognition phase
*/
canDeactivate(nextInstruction: ComponentInstruction): Promise<boolean> {
if (isBlank(this._currentInstruction)) {
return _resolveToTrue;
}
if (hasLifecycleHook(hookMod.canDeactivate, this._currentInstruction.componentType)) {
return PromiseWrapper.resolve(
this._componentRef.instance.canDeactivate(nextInstruction, this._currentInstruction));
}
return _resolveToTrue;
}
/**
* Called by Router during recognition phase
*/
canReuse(nextInstruction: ComponentInstruction): Promise<boolean> {
var result;
if (isBlank(this._currentInstruction) ||
this._currentInstruction.componentType != nextInstruction.componentType) {
result = false;
} else if (hasLifecycleHook(hookMod.canReuse, this._currentInstruction.componentType)) {
result = this._componentRef.instance.canReuse(nextInstruction, this._currentInstruction);
} else {
result = nextInstruction == this._currentInstruction ||
(isPresent(nextInstruction.params) && isPresent(this._currentInstruction.params) &&
StringMapWrapper.equals(nextInstruction.params, this._currentInstruction.params));
}
return PromiseWrapper.resolve(result).then((result) => {
// TODO: this is a hack
nextInstruction.reuse = result;
return result;
});
}
} }

View File

@ -105,6 +105,7 @@ function makeDummyLocation() {
function makeDummyRouter() { function makeDummyRouter() {
var dr = new SpyRouter(); var dr = new SpyRouter();
dr.spy('generate').andCallFake((routeParams) => dummyInstruction); dr.spy('generate').andCallFake((routeParams) => dummyInstruction);
dr.spy('isRouteActive').andCallFake((_) => false);
dr.spy('navigateInstruction'); dr.spy('navigateInstruction');
return dr; return dr;
} }

View File

@ -53,9 +53,9 @@ export function main() {
var outlet = makeDummyOutlet(); var outlet = makeDummyOutlet();
router.config([new Route({path: '/', component: DummyComponent})]) router.config([new Route({path: '/', component: DummyComponent})])
.then((_) => router.registerOutlet(outlet)) .then((_) => router.registerPrimaryOutlet(outlet))
.then((_) => { .then((_) => {
expect(outlet.spy('commit')).toHaveBeenCalled(); expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual([]); expect(location.urlChanges).toEqual([]);
async.done(); async.done();
}); });
@ -66,11 +66,11 @@ export function main() {
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet(); var outlet = makeDummyOutlet();
router.registerOutlet(outlet) router.registerPrimaryOutlet(outlet)
.then((_) => router.config([new Route({path: '/a', component: DummyComponent})])) .then((_) => router.config([new Route({path: '/a', component: DummyComponent})]))
.then((_) => router.navigate('/a')) .then((_) => router.navigate('/a'))
.then((_) => { .then((_) => {
expect(outlet.spy('commit')).toHaveBeenCalled(); expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual(['/a']); expect(location.urlChanges).toEqual(['/a']);
async.done(); async.done();
}); });
@ -80,11 +80,11 @@ export function main() {
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet(); var outlet = makeDummyOutlet();
router.registerOutlet(outlet) router.registerPrimaryOutlet(outlet)
.then((_) => router.config([new Route({path: '/b', component: DummyComponent})])) .then((_) => router.config([new Route({path: '/b', component: DummyComponent})]))
.then((_) => router.navigate('/b', true)) .then((_) => router.navigate('/b', true))
.then((_) => { .then((_) => {
expect(outlet.spy('commit')).toHaveBeenCalled(); expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual([]); expect(location.urlChanges).toEqual([]);
async.done(); async.done();
}); });
@ -94,14 +94,14 @@ export function main() {
it('should navigate after being configured', inject([AsyncTestCompleter], (async) => { it('should navigate after being configured', inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet(); var outlet = makeDummyOutlet();
router.registerOutlet(outlet) router.registerPrimaryOutlet(outlet)
.then((_) => router.navigate('/a')) .then((_) => router.navigate('/a'))
.then((_) => { .then((_) => {
expect(outlet.spy('commit')).not.toHaveBeenCalled(); expect(outlet.spy('activate')).not.toHaveBeenCalled();
return router.config([new Route({path: '/a', component: DummyComponent})]); return router.config([new Route({path: '/a', component: DummyComponent})]);
}) })
.then((_) => { .then((_) => {
expect(outlet.spy('commit')).toHaveBeenCalled(); expect(outlet.spy('activate')).toHaveBeenCalled();
async.done(); async.done();
}); });
})); }));
@ -142,13 +142,33 @@ export function main() {
inject([AsyncTestCompleter], (async) => { inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet(); var outlet = makeDummyOutlet();
router.registerOutlet(outlet); router.registerPrimaryOutlet(outlet);
router.config([new AsyncRoute({path: '/first', loader: loader, as: 'FirstCmp'})]); router.config([new AsyncRoute({path: '/first', loader: loader, as: 'FirstCmp'})]);
var instruction = router.generate(['/FirstCmp']); var instruction = router.generate(['/FirstCmp']);
router.navigateInstruction(instruction) router.navigateInstruction(instruction)
.then((_) => { .then((_) => {
expect(outlet.spy('commit')).toHaveBeenCalled(); expect(outlet.spy('activate')).toHaveBeenCalled();
async.done();
});
}));
it('should return whether a given instruction is active with isRouteActive',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) => router.config([
new Route({path: '/a', component: DummyComponent, as: 'A'}),
new Route({path: '/b', component: DummyComponent, as: 'B'})
]))
.then((_) => router.navigate('/a'))
.then((_) => {
var instruction = router.generate(['/A']);
var otherInstruction = router.generate(['/B']);
expect(router.isRouteActive(instruction)).toEqual(true);
expect(router.isRouteActive(otherInstruction)).toEqual(false);
async.done(); async.done();
}); });
})); }));
@ -213,7 +233,7 @@ function makeDummyOutlet() {
ref.spy('canActivate').andCallFake((_) => PromiseWrapper.resolve(true)); ref.spy('canActivate').andCallFake((_) => PromiseWrapper.resolve(true));
ref.spy('canReuse').andCallFake((_) => PromiseWrapper.resolve(false)); ref.spy('canReuse').andCallFake((_) => PromiseWrapper.resolve(false));
ref.spy('canDeactivate').andCallFake((_) => PromiseWrapper.resolve(true)); ref.spy('canDeactivate').andCallFake((_) => PromiseWrapper.resolve(true));
ref.spy('commit').andCallFake((_) => PromiseWrapper.resolve(true)); ref.spy('activate').andCallFake((_) => PromiseWrapper.resolve(true));
return ref; return ref;
} }