feat(router): add parent, children, firstChild to ActivatedRoute

This commit is contained in:
vsavkin 2016-08-02 14:34:00 -07:00 committed by Alex Rickabaugh
parent 5fceb21549
commit 550ab31bd0
4 changed files with 140 additions and 1 deletions

View File

@ -42,6 +42,7 @@ export class RouterState extends Tree<ActivatedRoute> {
root: TreeNode<ActivatedRoute>, public queryParams: Observable<Params>, root: TreeNode<ActivatedRoute>, public queryParams: Observable<Params>,
public fragment: Observable<string>, public snapshot: RouterStateSnapshot) { public fragment: Observable<string>, public snapshot: RouterStateSnapshot) {
super(root); super(root);
setRouterStateSnapshot<RouterState, ActivatedRoute>(this, root);
} }
toString(): string { return this.snapshot.toString(); } toString(): string { return this.snapshot.toString(); }
@ -95,6 +96,9 @@ export class ActivatedRoute {
_futureSnapshot: ActivatedRouteSnapshot; _futureSnapshot: ActivatedRouteSnapshot;
snapshot: ActivatedRouteSnapshot; snapshot: ActivatedRouteSnapshot;
/** @internal */
_routerState: RouterState;
/** /**
* @internal * @internal
*/ */
@ -107,6 +111,14 @@ export class ActivatedRoute {
get routeConfig(): Route { return this._futureSnapshot.routeConfig; } get routeConfig(): Route { return this._futureSnapshot.routeConfig; }
get parent(): ActivatedRoute { return this._routerState.parent(this); }
get firstChild(): ActivatedRoute { return this._routerState.firstChild(this); }
get children(): ActivatedRoute[] { return this._routerState.children(this); }
get pathFromRoot(): ActivatedRoute[] { return this._routerState.pathFromRoot(this); }
toString(): string { toString(): string {
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`; return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
} }
@ -168,6 +180,9 @@ export class ActivatedRouteSnapshot {
/** @internal */ /** @internal */
_resolve: InheritedResolve; _resolve: InheritedResolve;
/** @internal */
_routerState: RouterStateSnapshot;
/** /**
* @internal * @internal
*/ */
@ -183,6 +198,14 @@ export class ActivatedRouteSnapshot {
get routeConfig(): Route { return this._routeConfig; } get routeConfig(): Route { return this._routeConfig; }
get parent(): ActivatedRouteSnapshot { return this._routerState.parent(this); }
get firstChild(): ActivatedRouteSnapshot { return this._routerState.firstChild(this); }
get children(): ActivatedRouteSnapshot[] { return this._routerState.children(this); }
get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); }
toString(): string { toString(): string {
const url = this.url.map(s => s.toString()).join('/'); const url = this.url.map(s => s.toString()).join('/');
const matched = this._routeConfig ? this._routeConfig.path : ''; const matched = this._routeConfig ? this._routeConfig.path : '';
@ -213,17 +236,22 @@ export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
public url: string, root: TreeNode<ActivatedRouteSnapshot>, public queryParams: Params, public url: string, root: TreeNode<ActivatedRouteSnapshot>, public queryParams: Params,
public fragment: string) { public fragment: string) {
super(root); super(root);
setRouterStateSnapshot<RouterStateSnapshot, ActivatedRouteSnapshot>(this, root);
} }
toString(): string { return serializeNode(this._root); } toString(): string { return serializeNode(this._root); }
} }
function setRouterStateSnapshot<U, T extends{_routerState: U}>(state: U, node: TreeNode<T>): void {
node.value._routerState = state;
node.children.forEach(c => setRouterStateSnapshot(state, c));
}
function serializeNode(node: TreeNode<ActivatedRouteSnapshot>): string { function serializeNode(node: TreeNode<ActivatedRouteSnapshot>): string {
const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : ''; const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : '';
return `${node.value}${c}`; return `${node.value}${c}`;
} }
/** /**
* The expectation is that the activate route is created with the right set of parameters. * The expectation is that the activate route is created with the right set of parameters.
* So we push new values into the observables only when they are not the initial values. * So we push new values into the observables only when they are not the initial values.

View File

@ -14,21 +14,33 @@ export class Tree<T> {
get root(): T { return this._root.value; } get root(): T { return this._root.value; }
/**
* @deprecated (use ActivatedRoute.parent instead)
*/
parent(t: T): T { parent(t: T): T {
const p = this.pathFromRoot(t); const p = this.pathFromRoot(t);
return p.length > 1 ? p[p.length - 2] : null; return p.length > 1 ? p[p.length - 2] : null;
} }
/**
* @deprecated (use ActivatedRoute.children instead)
*/
children(t: T): T[] { children(t: T): T[] {
const n = findNode(t, this._root); const n = findNode(t, this._root);
return n ? n.children.map(t => t.value) : []; return n ? n.children.map(t => t.value) : [];
} }
/**
* @deprecated (use ActivatedRoute.firstChild instead)
*/
firstChild(t: T): T { firstChild(t: T): T {
const n = findNode(t, this._root); const n = findNode(t, this._root);
return n && n.children.length > 0 ? n.children[0].value : null; return n && n.children.length > 0 ? n.children[0].value : null;
} }
/**
* @deprecated
*/
siblings(t: T): T[] { siblings(t: T): T[] {
const p = findPath(t, this._root, []); const p = findPath(t, this._root, []);
if (p.length < 2) return []; if (p.length < 2) return [];
@ -37,6 +49,9 @@ export class Tree<T> {
return c.filter(cc => cc !== t); return c.filter(cc => cc !== t);
} }
/**
* @deprecated (use ActivatedRoute.pathFromRoot instead)
*/
pathFromRoot(t: T): T[] { return findPath(t, this._root, []).map(s => s.value); } pathFromRoot(t: T): T[] { return findPath(t, this._root, []).map(s => s.value); }
} }

View File

@ -0,0 +1,95 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from '../src/router_state';
import {TreeNode} from '../src/utils/tree';
describe('RouterState & Snapshot', () => {
describe('RouterStateSnapshot', () => {
let state: RouterStateSnapshot;
let a: ActivatedRouteSnapshot;
let b: ActivatedRouteSnapshot;
let c: ActivatedRouteSnapshot;
beforeEach(() => {
a = createActivatedRouteSnapshot('a');
b = createActivatedRouteSnapshot('b');
c = createActivatedRouteSnapshot('c');
const root = new TreeNode(a, [new TreeNode(b, []), new TreeNode(c, [])]);
state = new RouterStateSnapshot('url', root, {}, '');
});
it('should return first child', () => { expect(state.root.firstChild).toBe(b); });
it('should return children', () => {
const cc = state.root.children;
expect(cc[0]).toBe(b);
expect(cc[1]).toBe(c);
});
it('should return root', () => {
const b = state.root.firstChild;
expect(b.parent).toBe(state.root);
});
it('should return path from root', () => {
const b = state.root.firstChild;
const p = b.pathFromRoot;
expect(p[0]).toBe(state.root);
expect(p[1]).toBe(b);
});
});
describe('RouterState', () => {
let state: RouterState;
let a: ActivatedRoute;
let b: ActivatedRoute;
let c: ActivatedRoute;
beforeEach(() => {
a = createActivatedRoute('a');
b = createActivatedRoute('b');
c = createActivatedRoute('c');
const root = new TreeNode(a, [new TreeNode(b, []), new TreeNode(c, [])]);
state = new RouterState(root, <any>null, <any>null, <any>null);
});
it('should return first child', () => { expect(state.root.firstChild).toBe(b); });
it('should return children', () => {
const cc = state.root.children;
expect(cc[0]).toBe(b);
expect(cc[1]).toBe(c);
});
it('should return root', () => {
const b = state.root.firstChild;
expect(b.parent).toBe(state.root);
});
it('should return path from root', () => {
const b = state.root.firstChild;
const p = b.pathFromRoot;
expect(p[0]).toBe(state.root);
expect(p[1]).toBe(b);
});
});
});
function createActivatedRouteSnapshot(cmp: string) {
return new ActivatedRouteSnapshot(
<any>null, <any>null, <any>null, <any>null, <any>cmp, <any>null, <any>null, -1, null);
}
function createActivatedRoute(cmp: string) {
return new ActivatedRoute(<any>null, <any>null, <any>null, <any>null, <any>cmp, <any>null);
}

View File

@ -32,6 +32,7 @@
"test/create_router_state.spec.ts", "test/create_router_state.spec.ts",
"test/create_url_tree.spec.ts", "test/create_url_tree.spec.ts",
"test/config.spec.ts", "test/config.spec.ts",
"test/router_state.spec.ts",
"test/router.spec.ts", "test/router.spec.ts",
"../../../node_modules/@types/jasmine/index.d.ts" "../../../node_modules/@types/jasmine/index.d.ts"
] ]