From ded518d47f6555c779a2c34e3627601c9480ec5f Mon Sep 17 00:00:00 2001 From: vsavkin Date: Tue, 12 Jul 2016 09:49:55 -0700 Subject: [PATCH] feat(router): update routerLink DSL to handle aux routes --- .../@angular/router/src/create_url_tree.ts | 40 ++++++++++++++----- modules/@angular/router/src/router.ts | 3 ++ .../router/test/create_url_tree.spec.ts | 29 +++++++++++++- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/modules/@angular/router/src/create_url_tree.ts b/modules/@angular/router/src/create_url_tree.ts index 6e7d449d3d..6d9cb24b90 100644 --- a/modules/@angular/router/src/create_url_tree.ts +++ b/modules/@angular/router/src/create_url_tree.ts @@ -87,6 +87,20 @@ function normalizeCommands(commands: any[]): NormalizedNavigationCommands { for (let i = 0; i < commands.length; ++i) { const c = commands[i]; + if (typeof c === 'object' && c.outlets !== undefined) { + const r: {[k: string]: any} = {}; + forEach(c.outlets, (commands: any, name: string) => { + const n = name === '' ? PRIMARY_OUTLET : name; + if (typeof commands === 'string') { + r[n] = commands.split('/'); + } else { + r[n] = commands; + } + }); + res.push({outlets: r}); + continue; + } + if (!(typeof c === 'string')) { res.push(c); continue; @@ -140,15 +154,13 @@ function findStartingPosition( } function getPath(command: any): any { - if (!(typeof command === 'string')) return command.toString(); - const parts = command.toString().split(':'); - return parts.length > 1 ? parts[1] : command; + return `${command}`; } -function getOutlet(commands: any[]): string { - if (!(typeof commands[0] === 'string')) return PRIMARY_OUTLET; - const parts = commands[0].toString().split(':'); - return parts.length > 1 ? parts[0] : PRIMARY_OUTLET; +function getOutlets(commands: any[]): {[k: string]: any[]} { + if (!(typeof commands[0] === 'object')) return {[PRIMARY_OUTLET]: commands}; + if (commands[0].outlets === undefined) return {[PRIMARY_OUTLET]: commands}; + return commands[0].outlets; } function updateSegment(segment: UrlSegment, startIndex: number, commands: any[]): UrlSegment { @@ -177,11 +189,17 @@ function updateSegmentChildren( if (commands.length === 0) { return new UrlSegment(segment.pathsWithParams, {}); } else { - const outlet = getOutlet(commands); + const outlets = getOutlets(commands); const children: {[key: string]: UrlSegment} = {}; - children[outlet] = updateSegment(segment.children[outlet], startIndex, commands); + + forEach(outlets, (commands: any, outlet: string) => { + if (commands !== null) { + children[outlet] = updateSegment(segment.children[outlet], startIndex, commands); + } + }); + forEach(segment.children, (child: UrlSegment, childOutlet: string) => { - if (childOutlet !== outlet) { + if (outlets[childOutlet] === undefined) { children[childOutlet] = child; } }); @@ -201,7 +219,7 @@ function prefixedWith(segment: UrlSegment, startIndex: number, commands: any[]) const next = currentCommandIndex < commands.length - 1 ? commands[currentCommandIndex + 1] : null; - if (curr && next && (typeof next === 'object')) { + if (curr && next && (typeof next === 'object') && next.outlets === undefined) { if (!compare(curr, next, path)) return noMatch; currentCommandIndex += 2; } else { diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index 8ca4400262..e88bc493b8 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -209,6 +209,9 @@ export class Router { * // you can collapse static fragments like this * router.createUrlTree(['/team/33/user', userId]); * + * // create /team/33/(user/11//aux:chat) + * router.createUrlTree(['/team', 33, {outlets: {"": 'user/11', right: 'chat'}}]); + * * // assuming the current url is `/team/33/user/11` and the route points to `user/11` * * // navigate to /team/33/user/11/details diff --git a/modules/@angular/router/test/create_url_tree.spec.ts b/modules/@angular/router/test/create_url_tree.spec.ts index 5537c0736d..4f17275622 100644 --- a/modules/@angular/router/test/create_url_tree.spec.ts +++ b/modules/@angular/router/test/create_url_tree.spec.ts @@ -8,6 +8,7 @@ import {DefaultUrlSerializer, UrlPathWithParams, UrlSegment, UrlTree} from '../s describe('createUrlTree', () => { const serializer = new DefaultUrlSerializer(); + it('should navigate to the root', () => { const p = serializer.parse('/'); const t = createRoot(p, ['/']); @@ -42,16 +43,40 @@ describe('createUrlTree', () => { it('should support updating secondary segments', () => { const p = serializer.parse('/a(right:b)'); - const t = createRoot(p, ['right:c', 11, 'd']); + const t = createRoot(p, [{outlets: {right: ['c', 11, 'd']}}]); expect(serializer.serialize(t)).toEqual('/a(right:c/11/d)'); }); it('should support updating secondary segments (nested case)', () => { const p = serializer.parse('/a/(b//right:c)'); - const t = createRoot(p, ['a', 'right:d', 11, 'e']); + const t = createRoot(p, ['a', {outlets: {right: ['d', 11, 'e']}}]); expect(serializer.serialize(t)).toEqual('/a/(b//right:d/11/e)'); }); + it('should support updating using a string', () => { + const p = serializer.parse('/a(right:b)'); + const t = createRoot(p, [{outlets: {right: 'c/11/d'}}]); + expect(serializer.serialize(t)).toEqual('/a(right:c/11/d)'); + }); + + it('should support updating primary and secondary segments at once', () => { + const p = serializer.parse('/a(right:b)'); + const t = createRoot(p, [{outlets: {'': 'y/z', right: 'c/11/d'}}]); + expect(serializer.serialize(t)).toEqual('/y/z(right:c/11/d)'); + }); + + it('should support removing primary segment', () => { + const p = serializer.parse('/a/(b//right:c)'); + const t = createRoot(p, ['a', {outlets: {'': null, right: 'd'}}]); + expect(serializer.serialize(t)).toEqual('/a/(right:d)'); + }); + + it('should support removing secondary segments', () => { + const p = serializer.parse('/a(right:b)'); + const t = createRoot(p, [{outlets: {right: null}}]); + expect(serializer.serialize(t)).toEqual('/a'); + }); + it('should update matrix parameters', () => { const p = serializer.parse('/a;pp=11'); const t = createRoot(p, ['/a', {pp: 22, dd: 33}]);