Skip to content

Commit f31ead1

Browse files
btfordgoderbauer
authored andcommitted
feat(router): auxiliary routes
Closes angular#2775
1 parent e131650 commit f31ead1

24 files changed

+1470
-974
lines changed

modules/angular2/router.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export * from './src/router/route_config_decorator';
1919
export * from './src/router/route_definition';
2020
export {OnActivate, OnDeactivate, OnReuse, CanDeactivate, CanReuse} from './src/router/interfaces';
2121
export {CanActivate} from './src/router/lifecycle_annotations';
22-
export {Instruction} from './src/router/instruction';
22+
export {Instruction, ComponentInstruction} from './src/router/instruction';
23+
export {Url} from './src/router/url_parser';
2324

2425
import {LocationStrategy} from './src/router/location_strategy';
2526
import {HTML5LocationStrategy} from './src/router/html5_location_strategy';

modules/angular2/src/router/helpers.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.

modules/angular2/src/router/instruction.ts

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import {
66
List,
77
ListWrapper
88
} from 'angular2/src/facade/collection';
9-
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
9+
import {isPresent, isBlank, normalizeBlank, Type} from 'angular2/src/facade/lang';
10+
import {Promise} from 'angular2/src/facade/async';
1011

1112
import {PathRecognizer} from './path_recognizer';
13+
import {Url} from './url_parser';
1214

1315
export class RouteParams {
1416
constructor(public params: StringMap<string, string>) {}
@@ -18,34 +20,82 @@ export class RouteParams {
1820

1921

2022
/**
21-
* An `Instruction` represents the component hierarchy of the application based on a given route
23+
* `Instruction` is a tree of `ComponentInstructions`, with all the information needed
24+
* to transition each component in the app to a given route, including all auxiliary routes.
25+
*
26+
* This is a public API.
2227
*/
2328
export class Instruction {
24-
// "capturedUrl" is the part of the URL captured by this instruction
25-
// "accumulatedUrl" is the part of the URL captured by this instruction and all children
26-
accumulatedUrl: string;
27-
reuse: boolean = false;
28-
specificity: number;
29-
30-
constructor(public component: any, public capturedUrl: string,
31-
private _recognizer: PathRecognizer, public child: Instruction = null,
32-
private _params: StringMap<string, any> = null) {
33-
this.accumulatedUrl = capturedUrl;
34-
this.specificity = _recognizer.specificity;
35-
if (isPresent(child)) {
36-
this.child = child;
37-
this.specificity += child.specificity;
38-
var childUrl = child.accumulatedUrl;
39-
if (isPresent(childUrl)) {
40-
this.accumulatedUrl += childUrl;
41-
}
42-
}
29+
constructor(public component: ComponentInstruction, public child: Instruction,
30+
public auxInstruction: StringMap<string, Instruction>) {}
31+
32+
replaceChild(child: Instruction): Instruction {
33+
return new Instruction(this.component, child, this.auxInstruction);
34+
}
35+
}
36+
37+
/**
38+
* Represents a partially completed instruction during recognition that only has the
39+
* primary (non-aux) route instructions matched.
40+
*
41+
* `PrimaryInstruction` is an internal class used by `RouteRecognizer` while it's
42+
* figuring out where to navigate.
43+
*/
44+
export class PrimaryInstruction {
45+
constructor(public component: ComponentInstruction, public child: PrimaryInstruction,
46+
public auxUrls: List<Url>) {}
47+
}
48+
49+
export function stringifyInstruction(instruction: Instruction): string {
50+
var params = instruction.component.urlParams.length > 0 ?
51+
('?' + instruction.component.urlParams.join('&')) :
52+
'';
53+
54+
return instruction.component.urlPath + stringifyAux(instruction) +
55+
stringifyPrimary(instruction.child) + params;
56+
}
57+
58+
function stringifyPrimary(instruction: Instruction): string {
59+
if (isBlank(instruction)) {
60+
return '';
4361
}
62+
var params = instruction.component.urlParams.length > 0 ?
63+
(';' + instruction.component.urlParams.join(';')) :
64+
'';
65+
return '/' + instruction.component.urlPath + params + stringifyAux(instruction) +
66+
stringifyPrimary(instruction.child);
67+
}
4468

45-
params(): StringMap<string, string> {
46-
if (isBlank(this._params)) {
47-
this._params = this._recognizer.parseParams(this.capturedUrl);
48-
}
49-
return this._params;
69+
function stringifyAux(instruction: Instruction): string {
70+
var routes = [];
71+
StringMapWrapper.forEach(instruction.auxInstruction, (auxInstruction, _) => {
72+
routes.push(stringifyPrimary(auxInstruction));
73+
});
74+
if (routes.length > 0) {
75+
return '(' + routes.join('//') + ')';
5076
}
77+
return '';
78+
}
79+
80+
81+
/**
82+
* A `ComponentInstruction` represents the route state for a single component. An `Instruction` is
83+
* composed of a tree of these `ComponentInstruction`s.
84+
*
85+
* `ComponentInstructions` is a public API. Instances of `ComponentInstruction` are passed
86+
* to route lifecycle hooks, like {@link CanActivate}.
87+
*/
88+
export class ComponentInstruction {
89+
reuse: boolean = false;
90+
91+
constructor(public urlPath: string, public urlParams: List<string>,
92+
private _recognizer: PathRecognizer, public params: StringMap<string, any> = null) {}
93+
94+
get componentType() { return this._recognizer.handler.componentType; }
95+
96+
resolveComponentType(): Promise<Type> { return this._recognizer.handler.resolveComponentType(); }
97+
98+
get specificity() { return this._recognizer.specificity; }
99+
100+
get terminal() { return this._recognizer.terminal; }
51101
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Instruction} from './instruction';
1+
import {ComponentInstruction} from './instruction';
22
import {global} from 'angular2/src/facade/lang';
33

44
// This is here only so that after TS transpilation the file is not empty.
@@ -11,33 +11,33 @@ var __ignore_me = global;
1111
* Defines route lifecycle method [onActivate]
1212
*/
1313
export interface OnActivate {
14-
onActivate(nextInstruction: Instruction, prevInstruction: Instruction): any;
14+
onActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
1515
}
1616

1717
/**
1818
* Defines route lifecycle method [onReuse]
1919
*/
2020
export interface OnReuse {
21-
onReuse(nextInstruction: Instruction, prevInstruction: Instruction): any;
21+
onReuse(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
2222
}
2323

2424
/**
2525
* Defines route lifecycle method [onDeactivate]
2626
*/
2727
export interface OnDeactivate {
28-
onDeactivate(nextInstruction: Instruction, prevInstruction: Instruction): any;
28+
onDeactivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
2929
}
3030

3131
/**
3232
* Defines route lifecycle method [canReuse]
3333
*/
3434
export interface CanReuse {
35-
canReuse(nextInstruction: Instruction, prevInstruction: Instruction): any;
35+
canReuse(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
3636
}
3737

3838
/**
3939
* Defines route lifecycle method [canDeactivate]
4040
*/
4141
export interface CanDeactivate {
42-
canDeactivate(nextInstruction: Instruction, prevInstruction: Instruction): any;
42+
canDeactivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
4343
}

modules/angular2/src/router/lifecycle_annotations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import {makeDecorator} from 'angular2/src/util/decorators';
77
import {CanActivate as CanActivateAnnotation} from './lifecycle_annotations_impl';
88
import {Promise} from 'angular2/src/facade/async';
9-
import {Instruction} from 'angular2/src/router/instruction';
9+
import {ComponentInstruction} from 'angular2/src/router/instruction';
1010

1111
export {
1212
canReuse,
@@ -17,5 +17,5 @@ export {
1717
} from './lifecycle_annotations_impl';
1818

1919
export var CanActivate:
20-
(hook: (next: Instruction, prev: Instruction) => Promise<boolean>| boolean) => ClassDecorator =
20+
(hook: (next: ComponentInstruction, prev: ComponentInstruction) => Promise<boolean>| boolean) => ClassDecorator =
2121
makeDecorator(CanActivateAnnotation);

0 commit comments

Comments
 (0)