feat(router): add "paramsInheritanceStrategy" router configuration option

Previously, the router would merge path and matrix params, as well as
data/resolve, with special rules (only merging down when the route has
an empty path, or is component-less). This change adds an extra option
"paramsInheritanceStrategy" which, when set to 'always', makes child
routes unconditionally inherit params from parent routes.

Closes #20572.
This commit is contained in:
Zaven Muradyan
2017-11-28 16:57:10 -08:00
committed by Alex Rickabaugh
parent 5f23a1223f
commit 5efea2f6a0
10 changed files with 200 additions and 44 deletions
+13
View File
@@ -3794,6 +3794,19 @@ describe('Integration', () => {
});
});
describe('Testing router options', () => {
describe('paramsInheritanceStrategy', () => {
beforeEach(() => {
TestBed.configureTestingModule(
{imports: [RouterTestingModule.withRoutes([], {paramsInheritanceStrategy: 'always'})]});
});
it('should configure the router', fakeAsync(inject([Router], (router: Router) => {
expect(router.paramsInheritanceStrategy).toEqual('always');
})));
});
});
function expectEvents(events: Event[], pairs: any[]) {
expect(events.length).toEqual(pairs.length);
for (let i = 0; i < events.length; ++i) {
+56 -6
View File
@@ -8,7 +8,7 @@
import {Routes} from '../src/config';
import {recognize} from '../src/recognize';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../src/router_state';
import {ActivatedRouteSnapshot, ParamsInheritanceStrategy, RouterStateSnapshot, inheritedParamsDataResolve} from '../src/router_state';
import {PRIMARY_OUTLET, Params} from '../src/shared';
import {DefaultUrlSerializer, UrlTree} from '../src/url_tree';
@@ -201,7 +201,7 @@ describe('recognize', () => {
});
});
it('should merge componentless route\'s data', () => {
it('should inherit componentless route\'s data', () => {
checkRecognize(
[{
path: 'a',
@@ -214,6 +214,34 @@ describe('recognize', () => {
});
});
it('should not inherit route\'s data if it has component', () => {
checkRecognize(
[{
path: 'a',
component: ComponentA,
data: {one: 1},
children: [{path: 'b', data: {two: 2}, component: ComponentB}]
}],
'a/b', (s: RouterStateSnapshot) => {
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root)) !;
expect(r.data).toEqual({two: 2});
});
});
it('should inherit route\'s data if paramsInheritanceStrategy is \'always\'', () => {
checkRecognize(
[{
path: 'a',
component: ComponentA,
data: {one: 1},
children: [{path: 'b', data: {two: 2}, component: ComponentB}]
}],
'a/b', (s: RouterStateSnapshot) => {
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root)) !;
expect(r.data).toEqual({one: 1, two: 2});
}, 'always');
});
it('should set resolved data', () => {
checkRecognize(
[{path: 'a', resolve: {one: 'some-token'}, component: ComponentA}], 'a',
@@ -307,7 +335,7 @@ describe('recognize', () => {
});
});
it('should match (non-termianl) when both primary and secondary and primary has a child',
it('should match (non-terminal) when both primary and secondary and primary has a child',
() => {
const config = [{
path: 'parent',
@@ -579,7 +607,7 @@ describe('recognize', () => {
});
});
it('should merge params until encounters a normal route', () => {
it('should inherit params until encounters a normal route', () => {
checkRecognize(
[{
path: 'p/:id',
@@ -606,6 +634,25 @@ describe('recognize', () => {
checkActivatedRoute(c, 'c', {}, ComponentC);
});
});
it('should inherit all params if paramsInheritanceStrategy is \'always\'', () => {
checkRecognize(
[{
path: 'p/:id',
children: [{
path: 'a/:name',
children: [{
path: 'b',
component: ComponentB,
children: [{path: 'c', component: ComponentC}]
}]
}]
}],
'p/11/a/victor/b/c', (s: RouterStateSnapshot) => {
const c = s.firstChild(s.firstChild(s.firstChild(s.firstChild(s.root) !) !) !) !;
checkActivatedRoute(c, 'c', {id: '11', name: 'victor'}, ComponentC);
}, 'always');
});
});
describe('empty URL leftovers', () => {
@@ -722,8 +769,11 @@ describe('recognize', () => {
});
});
function checkRecognize(config: Routes, url: string, callback: any): void {
recognize(RootComponent, config, tree(url), url).subscribe(callback, e => { throw e; });
function checkRecognize(
config: Routes, url: string, callback: any,
paramsInheritanceStrategy?: ParamsInheritanceStrategy): void {
recognize(RootComponent, config, tree(url), url, paramsInheritanceStrategy)
.subscribe(callback, e => { throw e; });
}
function checkActivatedRoute(
+1 -1
View File
@@ -498,7 +498,7 @@ function checkResolveData(
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void {
const p = new PreActivation(future, curr, injector);
p.initialize(new ChildrenOutletContexts());
p.resolveData().subscribe(check, (e) => { throw e; });
p.resolveData('emptyOnly').subscribe(check, (e) => { throw e; });
}
function checkGuards(