在命名插座中传递参数不起作用
Passing parameters in named outlets is not working
伙计们,我在尝试使这段代码正常工作时遇到了一些问题。
基本上,我想将一些参数传递给嵌套并命名为 router-outlet
。
我正在使用以下 routerLink
:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
...
<router-outlet name="test"></router-outlet>
我的路线如下:
{
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
在 Whosebug 中搜索后,根据答案,这应该有效,但事实并非如此。有人对我所缺少的有任何了解吗?
提前致谢
编辑
我写了一篇文章,详细介绍了 Angular 11 附带的新修复程序:Angular Router: empty paths, named outlets and a fix that came with Angular 11。
TLDR;
详细解释
为什么它一开始就不起作用
A TLRD 因为具有(嵌套)空路径的命名插座并不总是 发挥良好(至少在较旧的版本)。这是其中一个案例。
首先,重要的是要提到 Angular 路由器如何处理路由及其更改。例如,它借助名为 UrlTree
1 的数据结构来跟踪当前的 URL。可以将 UrlTree 视为 URL 的 反序列化版本 ,它是一个字符串。给定一个 UrlTree
,将基于此 UrlTree
遍历路由配置数组(以 DFS 方式)。
UrlTree 的根是另一个结构,UrlSegmentGroup
:
constructor(
/** The URL segments of this group. See `UrlSegment` for more information */
public segments: UrlSegment[],
/** The list of children of this group */
public children: {[key: string]: UrlSegmentGroup}) {
forEach(children, (v: any, k: any) => v.parent = this);
如您所见,它类似于一个规则的树结构。来自 segments
数组的段包含 path
(例如 'crisis-center'
)和给定路径的矩阵参数。至于 children
属性,其键是 网点名称 (例如 'test'
),值是 UrlSegmentGroup
个实例.通过使用这些结构,Angular 路由器可以表示 URL 字符串并可以提供许多功能和自定义。
给定来自 crisis-center-routing.module.ts
的路由配置:
const crisisCenterRoutes: Routes = [
{
path: '', // (1)
component: CrisisCenterComponent,
children: [
{
path: '', // (2)
component: CrisisListComponent,
children: [
{
path: ':id', // (3)
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
]
}
];
将路由配置对象与 path: ':id'
匹配的 UrlTree
大致如下所示:
// Note: For simplicity, I've only used the `path` to represent the `segments` property
UrlTree {
// UrlSegmentGroup
root: {
children: {
primary: {
children: {
primary: {
children: {
test: {
children: {}
segments: [1], // Matches (3)
}
},
segments: [''], // Matches (1) and (2)
}
}
segments: ['crisis-center'],
}
}
segments: [],
}
}
注意:插座的默认名称是 'primary'
。
上面的UrlTree可以这样实现:
<a [routerLink]="['/crisis-center', { outlets: { primary: ['', { outlets: { test: [crisis.id] } }] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
虽然上述方法理论上应该可行,但实际上并不可行。那是因为 ''
没有 consumed 并且当发生这种情况时,将选择 primary
插座。更具体地说,来自 primary: ['' ...
的 ''
将与 (1)
匹配,但不会消耗第二个 ''
(来自 (2)
)。
但是,这似乎 to be fixed in Angular v12:
// At this point, not all paths of the `segment` array have been consumed.
// This time, the route's outlet is taken into account.
const matchedOnOutlet = getOutlet(route) === outlet;
const expanded$ = this.expandSegment(
childModule, segmentGroup, childConfig, slicedSegments,
matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
但是 this 过去是这样的:
// At this point, not all paths of the `segment` array have been consumed.
// As you can see, it always chooses the `primary` outlet
const expanded$ = this.expandSegment(
childModule, segmentGroup, childConfig, slicedSegments, PRIMARY_OUTLET, true);
由于您的版本较旧,我们需要找到另一种方法。
当前方法会发生类似的事情:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
但是这次导航不会成功,因为outlets之间会不匹配。它会在(2)
处失败,这里路由的出口是primary
,但是根据当时的UrlSegmentGroup
出口是test
.
一个解决方案
首先,我注意到 CrisisCenterComponent
的作用不大:
<h2>CRISIS CENTER</h2>
<router-outlet></router-outlet>
所以,我们将摆脱它。这就是我们将剩下的:
危机中心-routing.module.ts:
const crisisCenterRoutes: Routes = [
{
// path: '',
// component: CrisisCenterComponent,
// children: [
// {
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
// ]
// }
]
现在,由于 CrisisListComponent
充当容器,我们可以进行以下替换:
危机中心-routing.module.ts:
const crisisCenterRoutes: Routes = [
{
// path: '',
// component: CrisisCenterComponent,
// children: [
// {
// path: '',
// component: CrisisListComponent,
// children: [
// {
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
// ]
// }
// ]
// }
]
app-routing.module.ts
{
path: 'crisis-center',
loadChildren: () =>
import('./crisis-center/crisis-center.module').then(
mod => mod.CrisisCenterModule
),
data: { preload: true },
// !
component: CrisisListComponent
},
因此,不会有额外的 ''
(正如我们所见,有时会导致问题)匹配。
并且视图中的 routerLink
将保持不变:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
附带说明一下,现在当你 select 一个危机中心时, CrisisCenterHomeComponent
也会被激活。如果你想避免这种情况,你可以这样做:
危机中心-routing.module.ts:
/* ... */
{
path: ':id'
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
// Uncomment this if you want these 2 Route objects
// to be mutually exclusive(either one of them, not both at the same time)
pathMatch: 'full',
component: CrisisCenterHomeComponent
}
/* ... */
1: Angular Router: Getting to know UrlTree, ActivatedRouteSnapshot and ActivatedRoute
如果您想阅读更多关于 Angular 路由器及其内部 workings/features 的信息,我建议:
伙计们,我在尝试使这段代码正常工作时遇到了一些问题。
基本上,我想将一些参数传递给嵌套并命名为 router-outlet
。
我正在使用以下 routerLink
:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
...
<router-outlet name="test"></router-outlet>
我的路线如下:
{
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
在 Whosebug 中搜索后,根据答案,这应该有效,但事实并非如此。有人对我所缺少的有任何了解吗? 提前致谢
编辑
我写了一篇文章,详细介绍了 Angular 11 附带的新修复程序:Angular Router: empty paths, named outlets and a fix that came with Angular 11。
TLDR;
详细解释
为什么它一开始就不起作用
A TLRD 因为具有(嵌套)空路径的命名插座并不总是 发挥良好(至少在较旧的版本)。这是其中一个案例。
首先,重要的是要提到 Angular 路由器如何处理路由及其更改。例如,它借助名为 UrlTree
1 的数据结构来跟踪当前的 URL。可以将 UrlTree 视为 URL 的 反序列化版本 ,它是一个字符串。给定一个 UrlTree
,将基于此 UrlTree
遍历路由配置数组(以 DFS 方式)。
UrlTree 的根是另一个结构,UrlSegmentGroup
:
constructor(
/** The URL segments of this group. See `UrlSegment` for more information */
public segments: UrlSegment[],
/** The list of children of this group */
public children: {[key: string]: UrlSegmentGroup}) {
forEach(children, (v: any, k: any) => v.parent = this);
如您所见,它类似于一个规则的树结构。来自 segments
数组的段包含 path
(例如 'crisis-center'
)和给定路径的矩阵参数。至于 children
属性,其键是 网点名称 (例如 'test'
),值是 UrlSegmentGroup
个实例.通过使用这些结构,Angular 路由器可以表示 URL 字符串并可以提供许多功能和自定义。
给定来自 crisis-center-routing.module.ts
的路由配置:
const crisisCenterRoutes: Routes = [
{
path: '', // (1)
component: CrisisCenterComponent,
children: [
{
path: '', // (2)
component: CrisisListComponent,
children: [
{
path: ':id', // (3)
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
]
}
];
将路由配置对象与 path: ':id'
匹配的 UrlTree
大致如下所示:
// Note: For simplicity, I've only used the `path` to represent the `segments` property
UrlTree {
// UrlSegmentGroup
root: {
children: {
primary: {
children: {
primary: {
children: {
test: {
children: {}
segments: [1], // Matches (3)
}
},
segments: [''], // Matches (1) and (2)
}
}
segments: ['crisis-center'],
}
}
segments: [],
}
}
注意:插座的默认名称是 'primary'
。
上面的UrlTree可以这样实现:
<a [routerLink]="['/crisis-center', { outlets: { primary: ['', { outlets: { test: [crisis.id] } }] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
虽然上述方法理论上应该可行,但实际上并不可行。那是因为 ''
没有 consumed 并且当发生这种情况时,将选择 primary
插座。更具体地说,来自 primary: ['' ...
的 ''
将与 (1)
匹配,但不会消耗第二个 ''
(来自 (2)
)。
但是,这似乎 to be fixed in Angular v12:
// At this point, not all paths of the `segment` array have been consumed.
// This time, the route's outlet is taken into account.
const matchedOnOutlet = getOutlet(route) === outlet;
const expanded$ = this.expandSegment(
childModule, segmentGroup, childConfig, slicedSegments,
matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
但是 this 过去是这样的:
// At this point, not all paths of the `segment` array have been consumed.
// As you can see, it always chooses the `primary` outlet
const expanded$ = this.expandSegment(
childModule, segmentGroup, childConfig, slicedSegments, PRIMARY_OUTLET, true);
由于您的版本较旧,我们需要找到另一种方法。
当前方法会发生类似的事情:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
但是这次导航不会成功,因为outlets之间会不匹配。它会在(2)
处失败,这里路由的出口是primary
,但是根据当时的UrlSegmentGroup
出口是test
.
一个解决方案
首先,我注意到 CrisisCenterComponent
的作用不大:
<h2>CRISIS CENTER</h2>
<router-outlet></router-outlet>
所以,我们将摆脱它。这就是我们将剩下的:
危机中心-routing.module.ts:
const crisisCenterRoutes: Routes = [
{
// path: '',
// component: CrisisCenterComponent,
// children: [
// {
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
// ]
// }
]
现在,由于 CrisisListComponent
充当容器,我们可以进行以下替换:
危机中心-routing.module.ts:
const crisisCenterRoutes: Routes = [
{
// path: '',
// component: CrisisCenterComponent,
// children: [
// {
// path: '',
// component: CrisisListComponent,
// children: [
// {
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
// ]
// }
// ]
// }
]
app-routing.module.ts
{
path: 'crisis-center',
loadChildren: () =>
import('./crisis-center/crisis-center.module').then(
mod => mod.CrisisCenterModule
),
data: { preload: true },
// !
component: CrisisListComponent
},
因此,不会有额外的 ''
(正如我们所见,有时会导致问题)匹配。
并且视图中的 routerLink
将保持不变:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
附带说明一下,现在当你 select 一个危机中心时, CrisisCenterHomeComponent
也会被激活。如果你想避免这种情况,你可以这样做:
危机中心-routing.module.ts:
/* ... */
{
path: ':id'
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
// Uncomment this if you want these 2 Route objects
// to be mutually exclusive(either one of them, not both at the same time)
pathMatch: 'full',
component: CrisisCenterHomeComponent
}
/* ... */
1: Angular Router: Getting to know UrlTree, ActivatedRouteSnapshot and ActivatedRoute
如果您想阅读更多关于 Angular 路由器及其内部 workings/features 的信息,我建议: