Skip to content

Commit

Permalink
feat(router): implement Router.isRouteActive
Browse files Browse the repository at this point in the history
  • Loading branch information
btford committed Aug 31, 2015
1 parent e1a7e03 commit de37729
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 174 deletions.
59 changes: 19 additions & 40 deletions modules/angular1_router/src/ng_outlet.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,62 +132,41 @@ function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $
}
}

router.registerOutlet({
commit: function (instruction) {
router.registerPrimaryOutlet({
reuse: function (instruction) {
var next = $q.when(true);
var componentInstruction = instruction.component;
if (componentInstruction.reuse) {
var previousInstruction = currentInstruction;
currentInstruction = componentInstruction;
if (currentController.onReuse) {
next = $q.when(currentController.onReuse(currentInstruction, previousInstruction));
}
} else {
var self = this;
next = this.deactivate(instruction).then(function () {
return self.activate(componentInstruction);
});
var previousInstruction = currentInstruction;
currentInstruction = instruction;
if (currentController.onReuse) {
next = $q.when(currentController.onReuse(currentInstruction, previousInstruction));
}
return next.then(function () {
if (childRouter) {
return childRouter.commit(instruction.child);
} else {
return $q.when(true);
}
});

return next;
},
canReuse: function (nextInstruction) {
var result;
var componentInstruction = nextInstruction.component;
if (!currentInstruction ||
currentInstruction.componentType !== componentInstruction.componentType) {
currentInstruction.componentType !== nextInstruction.componentType) {
result = false;
} else if (currentController.canReuse) {
result = currentController.canReuse(componentInstruction, currentInstruction);
result = currentController.canReuse(nextInstruction, currentInstruction);
} else {
result = componentInstruction === currentInstruction ||
angular.equals(componentInstruction.params, currentInstruction.params);
result = nextInstruction === currentInstruction ||
angular.equals(nextInstruction.params, currentInstruction.params);
}
return $q.when(result).then(function (result) {
// TODO: this is a hack
componentInstruction.reuse = result;
return result;
});
return $q.when(result);
},
canDeactivate: function (instruction) {
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);
},
deactivate: function (instruction) {
// todo(shahata): childRouter.dectivate, dispose component?
var result = $q.when();
return result.then(function () {
if (currentController && currentController.onDeactivate) {
return currentController.onDeactivate(instruction && instruction.component, currentInstruction);
}
});
if (currentController && currentController.onDeactivate) {
return $q.when(currentController.onDeactivate(instruction, currentInstruction));
}
return $q.when();
},
activate: function (instruction) {
var previousInstruction = currentInstruction;
Expand Down Expand Up @@ -228,7 +207,7 @@ function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $
}
});
}
}, outletName);
});
}
}

Expand Down
143 changes: 118 additions & 25 deletions modules/angular2/src/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,16 @@ export class Router {
lastNavigationAttempt: string;

private _currentInstruction: Instruction = null;

private _currentNavigation: Promise<any> = _resolveToTrue;
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();


constructor(public registry: RouteRegistry, public _pipeline: Pipeline, public parent: Router,
public hostComponent: any) {}

Expand All @@ -67,26 +72,75 @@ export class Router {
* Constructs a child router. You probably don't need to use this unless you're writing a reusable
* component.
*/
childRouter(hostComponent: any): Router { return new ChildRouter(this, hostComponent); }
childRouter(hostComponent: any): Router {
return this._childRouter = new ChildRouter(this, hostComponent);
}


/**
* Constructs a child router. You probably don't need to use this unless you're writing a reusable
* component.
*/
auxRouter(hostComponent: any): Router { return new ChildRouter(this, hostComponent); }

/**
* Register an object to notify of route changes. You probably don't need to use this unless
* you're writing a reusable component.
* Register an outlet to notified of primary route changes.
*
* You probably don't need to use this unless you're writing a reusable component.
*/
registerOutlet(outlet: RouterOutlet): Promise<boolean> {
registerPrimaryOutlet(outlet: RouterOutlet): Promise<boolean> {
if (isPresent(outlet.name)) {
this._auxOutlets.set(outlet.name, outlet);
} else {
this._outlet = outlet;
throw new BaseException(`registerAuxOutlet expects to be called with an unnamed outlet.`);
}

this._outlet = outlet;
if (isPresent(this._currentInstruction)) {
return outlet.commit(this._currentInstruction);
return this.commit(this._currentInstruction, false);
}
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.
*
Expand Down Expand Up @@ -143,7 +197,7 @@ export class Router {

_navigate(instruction: Instruction, _skipLocationChange: boolean): Promise<any> {
return this._settleInstruction(instruction)
.then((_) => this._reuse(instruction))
.then((_) => this._canReuse(instruction))
.then((_) => this._canActivate(instruction))
.then((result) => {
if (!result) {
Expand Down Expand Up @@ -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)) {
return _resolveToFalse;
}
return this._outlet.canReuse(instruction)
return this._outlet.canReuse(instruction.component)
.then((result) => {
if (isPresent(this._outlet.childRouter) && isPresent(instruction.child)) {
return this._outlet.childRouter._reuse(instruction.child);
if (isPresent(this._childRouter) && isPresent(instruction.child)) {
return this._childRouter._canReuse(instruction.child);
}
});
}
Expand All @@ -211,19 +268,26 @@ export class Router {
return _resolveToTrue;
}
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;
} else {
next = this._outlet.canDeactivate(instruction);
next = this._outlet.canDeactivate(componentInstruction);
}
// TODO: aux route lifecycle hooks
return next.then((result) => {
if (result == false) {
return false;
}
if (isPresent(this._outlet.childRouter)) {
return this._outlet.childRouter._canDeactivate(isPresent(instruction) ? instruction.child :
null);
if (isPresent(this._childRouter)) {
return this._childRouter._canDeactivate(childInstruction);
}
return true;
});
Expand All @@ -234,13 +298,29 @@ export class Router {
*/
commit(instruction: Instruction, _skipLocationChange: boolean = false): Promise<any> {
this._currentInstruction = instruction;
var next = _resolveToTrue;
var next: Promise<any> = _resolveToTrue;
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 = [];
MapWrapper.forEach(this._auxOutlets,
(outlet, _) => { promises.push(outlet.commit(instruction)); });
MapWrapper.forEach(this._auxRouters, (router, name) => {
promises.push(router.commit(instruction.auxInstruction[name]));
});

return next.then((_) => PromiseWrapper.all(promises));
}

Expand All @@ -262,10 +342,23 @@ export class Router {
* Removes the contents of this router's outlet and all descendant outlets
*/
deactivate(instruction: Instruction): Promise<any> {
var childInstruction: Instruction = null;
var componentInstruction: ComponentInstruction = null;
if (isPresent(instruction)) {
childInstruction = instruction.child;
componentInstruction = instruction.component;
}
var next: Promise<any> = _resolveToTrue;
if (isPresent(this._childRouter)) {
next = this._childRouter.deactivate(childInstruction);
}
if (isPresent(this._outlet)) {
return this._outlet.deactivate(instruction);
next = next.then((_) => this._outlet.deactivate(componentInstruction));
}
return _resolveToTrue;

// TODO: handle aux routes

return next;
}


Expand Down
Loading

0 comments on commit de37729

Please sign in to comment.