feat(router): add parent, children, firstChild to ActivatedRoute
This commit is contained in:
parent
5fceb21549
commit
550ab31bd0
|
@ -42,6 +42,7 @@ export class RouterState extends Tree<ActivatedRoute> {
|
|||
root: TreeNode<ActivatedRoute>, public queryParams: Observable<Params>,
|
||||
public fragment: Observable<string>, public snapshot: RouterStateSnapshot) {
|
||||
super(root);
|
||||
setRouterStateSnapshot<RouterState, ActivatedRoute>(this, root);
|
||||
}
|
||||
|
||||
toString(): string { return this.snapshot.toString(); }
|
||||
|
@ -95,6 +96,9 @@ export class ActivatedRoute {
|
|||
_futureSnapshot: ActivatedRouteSnapshot;
|
||||
snapshot: ActivatedRouteSnapshot;
|
||||
|
||||
/** @internal */
|
||||
_routerState: RouterState;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -107,6 +111,14 @@ export class ActivatedRoute {
|
|||
|
||||
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 {
|
||||
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
|
||||
}
|
||||
|
@ -168,6 +180,9 @@ export class ActivatedRouteSnapshot {
|
|||
/** @internal */
|
||||
_resolve: InheritedResolve;
|
||||
|
||||
/** @internal */
|
||||
_routerState: RouterStateSnapshot;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -183,6 +198,14 @@ export class ActivatedRouteSnapshot {
|
|||
|
||||
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 {
|
||||
const url = this.url.map(s => s.toString()).join('/');
|
||||
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 fragment: string) {
|
||||
super(root);
|
||||
setRouterStateSnapshot<RouterStateSnapshot, ActivatedRouteSnapshot>(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 {
|
||||
const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : '';
|
||||
return `${node.value}${c}`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -14,21 +14,33 @@ export class Tree<T> {
|
|||
|
||||
get root(): T { return this._root.value; }
|
||||
|
||||
/**
|
||||
* @deprecated (use ActivatedRoute.parent instead)
|
||||
*/
|
||||
parent(t: T): T {
|
||||
const p = this.pathFromRoot(t);
|
||||
return p.length > 1 ? p[p.length - 2] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (use ActivatedRoute.children instead)
|
||||
*/
|
||||
children(t: T): T[] {
|
||||
const n = findNode(t, this._root);
|
||||
return n ? n.children.map(t => t.value) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (use ActivatedRoute.firstChild instead)
|
||||
*/
|
||||
firstChild(t: T): T {
|
||||
const n = findNode(t, this._root);
|
||||
return n && n.children.length > 0 ? n.children[0].value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
siblings(t: T): T[] {
|
||||
const p = findPath(t, this._root, []);
|
||||
if (p.length < 2) return [];
|
||||
|
@ -37,6 +49,9 @@ export class Tree<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); }
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
"test/create_router_state.spec.ts",
|
||||
"test/create_url_tree.spec.ts",
|
||||
"test/config.spec.ts",
|
||||
"test/router_state.spec.ts",
|
||||
"test/router.spec.ts",
|
||||
"../../../node_modules/@types/jasmine/index.d.ts"
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue