fix(router): correctly handle string command in outlets (#39728)
There are many places where examples use just a string for the command in outlets. When using nested outlets, we do not correctly handle this case, as the types and algorithm always expect an array. This PR updates the `createUrlTree` algorithm to account for the possibility of a string literal as the command for an outlet. Fixes #18928 PR Close #39728
This commit is contained in:
parent
969ad329de
commit
c33a8235d9
|
@ -186,7 +186,7 @@ function createPositionApplyingDoubleDots(
|
||||||
return new Position(g, false, ci - dd);
|
return new Position(g, false, ci - dd);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOutlets(commands: any[]): {[k: string]: any[]} {
|
function getOutlets(commands: unknown[]): {[k: string]: unknown[]|string} {
|
||||||
if (isCommandWithOutlets(commands[0])) {
|
if (isCommandWithOutlets(commands[0])) {
|
||||||
return commands[0].outlets;
|
return commands[0].outlets;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,10 @@ function updateSegmentGroupChildren(
|
||||||
const outlets = getOutlets(commands);
|
const outlets = getOutlets(commands);
|
||||||
const children: {[key: string]: UrlSegmentGroup} = {};
|
const children: {[key: string]: UrlSegmentGroup} = {};
|
||||||
|
|
||||||
forEach(outlets, (commands: any, outlet: string) => {
|
forEach(outlets, (commands, outlet) => {
|
||||||
|
if (typeof commands === 'string') {
|
||||||
|
commands = [commands];
|
||||||
|
}
|
||||||
if (commands !== null) {
|
if (commands !== null) {
|
||||||
children[outlet] = updateSegmentGroup(segmentGroup.children[outlet], startIndex, commands);
|
children[outlet] = updateSegmentGroup(segmentGroup.children[outlet], startIndex, commands);
|
||||||
}
|
}
|
||||||
|
@ -311,9 +314,13 @@ function createNewSegmentGroup(
|
||||||
return new UrlSegmentGroup(paths, {});
|
return new UrlSegmentGroup(paths, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewSegmentChildren(outlets: {[name: string]: any}): any {
|
function createNewSegmentChildren(outlets: {[name: string]: unknown[]|string}):
|
||||||
const children: {[key: string]: UrlSegmentGroup} = {};
|
{[outlet: string]: UrlSegmentGroup} {
|
||||||
forEach(outlets, (commands: any, outlet: string) => {
|
const children: {[outlet: string]: UrlSegmentGroup} = {};
|
||||||
|
forEach(outlets, (commands, outlet) => {
|
||||||
|
if (typeof commands === 'string') {
|
||||||
|
commands = [commands];
|
||||||
|
}
|
||||||
if (commands !== null) {
|
if (commands !== null) {
|
||||||
children[outlet] = createNewSegmentGroup(new UrlSegmentGroup([], {}), 0, commands);
|
children[outlet] = createNewSegmentGroup(new UrlSegmentGroup([], {}), 0, commands);
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,13 @@ describe('createUrlTree', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can navigate to nested route where commands is string', () => {
|
||||||
|
const p = serializer.parse('/');
|
||||||
|
const t = createRoot(
|
||||||
|
p, ['/', {outlets: {primary: ['child', {outlets: {primary: 'nested-primary'}}]}}]);
|
||||||
|
expect(serializer.serialize(t)).toEqual('/child/nested-primary');
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw when outlets is not the last command', () => {
|
it('should throw when outlets is not the last command', () => {
|
||||||
const p = serializer.parse('/a');
|
const p = serializer.parse('/a');
|
||||||
expect(() => createRoot(p, ['a', {outlets: {right: ['c']}}, 'c']))
|
expect(() => createRoot(p, ['a', {outlets: {right: ['c']}}, 'c']))
|
||||||
|
|
Loading…
Reference in New Issue