diff --git a/packages/router/src/create_url_tree.ts b/packages/router/src/create_url_tree.ts index 7e5d0c09853..1f006609825 100644 --- a/packages/router/src/create_url_tree.ts +++ b/packages/router/src/create_url_tree.ts @@ -339,8 +339,9 @@ function updateSegmentGroupChildren( const outlets = getOutlets(commands); const children: {[key: string]: UrlSegmentGroup} = {}; // If the set of commands does not apply anything to the primary outlet and the child segment is - // an empty path primary segment on its own, we want to skip applying the commands at this - // level. Imagine the following config: + // an empty path primary segment on its own, we want to apply the commands to the empty child + // path rather than here. The outcome is that the empty primary child is effectively removed + // from the final output UrlTree. Imagine the following config: // // {path: '', children: [{path: '**', outlet: 'popup'}]}. // @@ -361,8 +362,9 @@ function updateSegmentGroupChildren( if (!outlets[PRIMARY_OUTLET] && segmentGroup.children[PRIMARY_OUTLET] && segmentGroup.numberOfChildren === 1 && segmentGroup.children[PRIMARY_OUTLET].segments.length === 0) { - return updateSegmentGroupChildren( - segmentGroup.children[PRIMARY_OUTLET], startIndex, commands); + const childrenOfEmptyChild = + updateSegmentGroupChildren(segmentGroup.children[PRIMARY_OUTLET], startIndex, commands); + return new UrlSegmentGroup(segmentGroup.segments, childrenOfEmptyChild.children); } Object.entries(outlets).forEach(([outlet, commands]) => { diff --git a/packages/router/test/create_url_tree.spec.ts b/packages/router/test/create_url_tree.spec.ts index 311eb67b3f9..62295bda4e5 100644 --- a/packages/router/test/create_url_tree.spec.ts +++ b/packages/router/test/create_url_tree.spec.ts @@ -206,6 +206,32 @@ describe('createUrlTree', async () => { expect(serializer.serialize(t)).toEqual('/parent/child(rootSecondary:rootPopup)'); }); + it('works with named children of empty path primary, relative to non-empty parent', + async () => { + router.resetConfig([{ + path: 'case', + component: class {}, + children: [ + { + path: '', + component: class {}, + children: [ + {path: 'foo', outlet: 'foo', children: []}, + ], + }, + ] + }]); + await router.navigateByUrl('/case'); + expect(router.url).toEqual('/case'); + expect(router + .createUrlTree( + [{outlets: {'foo': ['foo']}}], + // relative to the 'case' route + {relativeTo: router.routerState.root.firstChild}) + .toString()) + .toEqual('/case/(foo:foo)'); + }); + describe('absolute navigations', () => { it('with and pathless root', async () => { router.resetConfig([