Angular 8 边缘情况:ActivatedRoute#data 上的奇怪值(解析父级,子级数据 => 子级数据被覆盖)
Angular 8 edge case: Weird value on ActivatedRoute#data (resolve on parent, data on child => child data gets overwritten)
我在实现一个简单的面包屑组件时偶然发现了这个问题。
我们的想法是在路线的 data
属性 上附加 breadcrumb
数据。对于静态值,效果很好:
const routes: Route[] = [
// ...
{ path: 'outer', data: { breadcrumb: 'outer' }, component: OuterComponent, children: [
{ path: '', pathMatch: 'full', data: { breadcrumb: 'inner' }, component: InnerComponent }
] }
// ...
];
这给了我 'outer'
和 'inner'
相应的 ActivatedRoute
s。
对于动态值,解析器服务似乎是一个很好的解决方案。这也很有效,如果不是一个(奇怪的?)边缘案例:
const routes: Route[] = [
// ...
{ path: 'outer', resolve: { breadcrumb: OuterResolverService }, component: OuterComponent, children: [
{ path: '', pathMatch: 'full', data: { breadcrumb: 'inner' }, component: InnerComponent }
] },
// ...
];
这为相应的 ActivatedRoute
提供了 'outer'
和 'outer'
(再次)。这让我很惊讶。
Note: It does work as expected when the inner component has any path but ''
. pathMatch: 'full'
doesn't seem to be an influencing factor. I found the following configuration as a working workaround:
{ path: 'outer', resolve: { breadcrumb: 'outer' }, component: OuterComponent, children: [
{ path: 'inner', data: { breadcrumb: 'inner' }, component: InnerComponent },
{ path: '', pathMatch: 'full', redirectTo: 'inner' }
]}
不过,这让我想知道:
我是否误解了 data
/resolve
机制的工作原理? (在我看来,从官方文档来看,这应该是一个预期的用例,但显然它并没有像我认为的那样工作。)
这种行为是预期的吗?
或者这是 Angular 8 中的错误?
作为参考,stackblitz 演示了这个问题:Stackblitz
Angular提供2种路由参数继承模式,默认为emptyOnly
,表示只有空路径会继承其parent参数(参数包括数据和解析数据)。 (另一种模式是 always
,这意味着 children 总是继承 parent 参数,这对你没有帮助)
在这种情况下,您有一个空的 child 路径,因此它继承了它的 parent 参数,但是,通常情况下, child 数据应该优先于继承的数据,如果它们有一个匹配的密钥,就像在您的静态数据案例中一样。
但是,问题是解析数据总是会覆盖静态数据,无论是否继承(如果您有静态数据并且由于某种原因在同一路由上使用相同的密钥解析数据,则静态数据将被覆盖),因此解析后的数据会覆盖已解析 parent 数据案例中的 child 数据,但不会覆盖静态案例中的数据。或者,如果您在两个级别都有解析器,则 child 的已解析数据将优先。
所以这不是 "bug",而是一种古怪的行为。也许值得用 angular 提高,因为优先顺序似乎是:child 解析数据,parent 解析数据,child 数据,parent 数据.. . 什么时候(对我来说):child 解析数据,child 数据,parent 解析数据,parent 数据。尽管我可以看到两种方式的争论,因为 child 在技术上继承了 parents 解析的数据,这些数据应该会覆盖任何静态数据。
解决方法是可行的,因为从技术上讲,您的 child 路径不是空路径。你只是在欺骗路由器不让 child 继承。
您可以使用一个略有不同的解决方法,即使用不同的关键字并让您感兴趣的面包屑组件检查两者,如下所示:
{
path: 'not-working',
component: OuterComponent,
resolve: { resolvedBreadcrumb: OuterResolverService },
children: [
{
path: '',
pathMatch: 'full',
component: InnerComponent,
data: { breadcrumb: 'inner' }
}
]
},
和:
const crumb = route.snapshot.data['breadcrumb'] || route.snapshot.data['resolvedBreadcrumb'];
其工作原理如下所示:https://stackblitz.com/edit/angular-pmw6x1?file=src%2Fapp%2Fapp.module.ts
我在实现一个简单的面包屑组件时偶然发现了这个问题。
我们的想法是在路线的 data
属性 上附加 breadcrumb
数据。对于静态值,效果很好:
const routes: Route[] = [
// ...
{ path: 'outer', data: { breadcrumb: 'outer' }, component: OuterComponent, children: [
{ path: '', pathMatch: 'full', data: { breadcrumb: 'inner' }, component: InnerComponent }
] }
// ...
];
这给了我 'outer'
和 'inner'
相应的 ActivatedRoute
s。
对于动态值,解析器服务似乎是一个很好的解决方案。这也很有效,如果不是一个(奇怪的?)边缘案例:
const routes: Route[] = [
// ...
{ path: 'outer', resolve: { breadcrumb: OuterResolverService }, component: OuterComponent, children: [
{ path: '', pathMatch: 'full', data: { breadcrumb: 'inner' }, component: InnerComponent }
] },
// ...
];
这为相应的 ActivatedRoute
提供了 'outer'
和 'outer'
(再次)。这让我很惊讶。
Note: It does work as expected when the inner component has any path but
''
.pathMatch: 'full'
doesn't seem to be an influencing factor. I found the following configuration as a working workaround:{ path: 'outer', resolve: { breadcrumb: 'outer' }, component: OuterComponent, children: [ { path: 'inner', data: { breadcrumb: 'inner' }, component: InnerComponent }, { path: '', pathMatch: 'full', redirectTo: 'inner' } ]}
不过,这让我想知道:
我是否误解了
data
/resolve
机制的工作原理? (在我看来,从官方文档来看,这应该是一个预期的用例,但显然它并没有像我认为的那样工作。)这种行为是预期的吗?
或者这是 Angular 8 中的错误?
作为参考,stackblitz 演示了这个问题:Stackblitz
Angular提供2种路由参数继承模式,默认为emptyOnly
,表示只有空路径会继承其parent参数(参数包括数据和解析数据)。 (另一种模式是 always
,这意味着 children 总是继承 parent 参数,这对你没有帮助)
在这种情况下,您有一个空的 child 路径,因此它继承了它的 parent 参数,但是,通常情况下, child 数据应该优先于继承的数据,如果它们有一个匹配的密钥,就像在您的静态数据案例中一样。
但是,问题是解析数据总是会覆盖静态数据,无论是否继承(如果您有静态数据并且由于某种原因在同一路由上使用相同的密钥解析数据,则静态数据将被覆盖),因此解析后的数据会覆盖已解析 parent 数据案例中的 child 数据,但不会覆盖静态案例中的数据。或者,如果您在两个级别都有解析器,则 child 的已解析数据将优先。
所以这不是 "bug",而是一种古怪的行为。也许值得用 angular 提高,因为优先顺序似乎是:child 解析数据,parent 解析数据,child 数据,parent 数据.. . 什么时候(对我来说):child 解析数据,child 数据,parent 解析数据,parent 数据。尽管我可以看到两种方式的争论,因为 child 在技术上继承了 parents 解析的数据,这些数据应该会覆盖任何静态数据。
解决方法是可行的,因为从技术上讲,您的 child 路径不是空路径。你只是在欺骗路由器不让 child 继承。
您可以使用一个略有不同的解决方法,即使用不同的关键字并让您感兴趣的面包屑组件检查两者,如下所示:
{
path: 'not-working',
component: OuterComponent,
resolve: { resolvedBreadcrumb: OuterResolverService },
children: [
{
path: '',
pathMatch: 'full',
component: InnerComponent,
data: { breadcrumb: 'inner' }
}
]
},
和:
const crumb = route.snapshot.data['breadcrumb'] || route.snapshot.data['resolvedBreadcrumb'];
其工作原理如下所示:https://stackblitz.com/edit/angular-pmw6x1?file=src%2Fapp%2Fapp.module.ts