Angular路由器:如何将数据传递给延迟加载模块?
Angular router: how to pass data to lazy loading module?
我的 Angular 应用程序的一个模块有以下路由路径:
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'documents',
data: { myObject: MyConstants.OPTION_ONE },
children: [
{
path: ':ID_DOC',
children: [
{ path: 'edit', component: EditDocumentComponent },
{ path: '', component: DocumentDetailsComponent },
]
},
{ path: 'add', component: AddDocumentComponent },
{ path: '', component: DocumentsListComponent }
]
}
])
],
exports: [
RouterModule
]
})
export class DocumentsManagementRoutingModule {
}
如您所见,我使用 data
属性 将一些数据传递到 "documents" 中的每个路径,因此我可以从路由路径中声明的任何组件中获取它:
例如,这是我在 DocumentDetailsComponent
中获取数据的方式:
export class DocumentDetailsComponent implements OnDestroy {
private obsData: Subscription;
private option: any;
constructor(private route: ActivatedRoute) {
this.obsData = this.route.data.subscribe(data => {
this.option = data['myObject'];
});
}
ngOnDestroy(): void {
this.obsData.unsubscribe();
}
}
现在我改变了整个应用程序的路由结构,我从其他模块调用上面的模块,在延迟加载中,使用 loadChildren
属性。我以同样的方式传递数据:
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'users',
loadChildren: 'app/documents/documents.module#DocumentsModule',
data: { myObject: MyConstants.OPTION_ONE }},
{
path: ':ID_USER',
children: [
{ path: 'edit', component: EditUserComponent },
{ path: '', component: UserDetailsComponent },
]
},
{ path: 'add', component: AddUserComponent },
{ path: '', component: UserListComponent }
])
],
exports: [
RouterModule
]
})
export class UsersManagementRoutingModule {
}
我对调用 DocumentsManagementRoutingModule
的所有其他模块也做了同样的事情,将 myObject
属性 更改为 MyConstants.OPTION_TWO
、MyConstants.OPTION_THREE
等等,根据我的需要。
那么,由于不知道调用我的懒加载模块的模块及其相关路径,如何从调用模块获取data
属性?
为什么不使用服务在模块或任何组件之间共享数据。您可以在主模块提供程序中导入此服务,因此可以在所有其他模块(延迟加载模块)中使用并共享数据。
该服务可以具有设置和获取值的功能,因此您可以在服务中使用这些功能来获取所需的数据
我想我可能明白问题在问什么了。
问题
这是@smartmouse提供的plunker的路由图。
- home
- shop
- contact
- map
- about
home
路由配置中配置了一个 data
对象。直接子路由可以访问这个数据对象。问题是,非直接子 map
想要访问 data
对象,但显然,它不能。
而且我们可以知道@smartmouse 想要更进一步——嵌套的非直接子路由可以访问来自祖先的数据。
为什么不能?
查看我修改过的plunker。 https://plnkr.co/edit/FA7mGmspUXHhU8YvgDpT
你可以看到我为contact
定义了一个额外的子组件DefaultComponent
。表明它是路由contact
的直接和默认子路由,可以解释为它也是上级路由home
的直接子路由。因此,它可以访问 data
对象。
解决方案
再看看我提供的插件
NOTE: The Angular packages I'm using is v4.3.0
方法 #1 -- 查询参数
我在 home.component.ts
中为 contact
路由定义了一些查询参数。你可以看看如何使用它。
优点:
- 您可以跨任何级别的路由访问查询参数。
- 与延迟加载模块配合得很好
缺点:
您不能在路由配置中定义查询参数。
但是你可以使用一些路由生命周期钩子来为目标祖先路由定义它们
方法 #2 -- 服务
在应用程序的 顶层 上定义数据共享服务作为单例模式。另外,使用一些实用程序来防止它被启动两次。然后你可以将一些数据放入其中,并在任何地方检索它。
优点:
- 通过 DI 全局可见;
- 与延迟加载模块配合得很好
缺点:
- 您无法更新路由配置中的数据。
- 您必须在其他地方定义数据。如果你不能控制它的来源,那可能是个问题。
方法 #3 -- 路由解析
有人可能会发现我还在 plunker 中定义了 resolve
示例代码。这是为了表明它与路由配置中的 data
具有相同的行为,除了它实际上是用于动态数据检索。
https://vsavkin.com/angular-router-understanding-router-state-7b5b95a12eab#5400
The data property is used for passing a fixed object to an activated route. It does not change throughout the lifetime of the application. The resolve property is used for dynamic data.
以@smartmouse的plunkr为例
我们在 'home' 路由配置中定义了 data
。我们可以在ContactModule
中为contact的默认路由定义一个数据解析器,代理从上级路由传过来的数据。然后它的所有直接子路由都可以访问 resolved 数据对象。
优点:
- 适用于任何级别的嵌套路由
- 与延迟加载模块配合得很好
缺点:
- 您可能必须在其子路由想要访问该数据的每个父路由中声明解析 属性。这是一种肮脏的工作。
目前还没有完美通用的解决方案,常用Angular。有人应该权衡利弊,选择合适的。
您可以使用activatedRoute.pathFromRoot遍历父路由,并从最近的可用祖先获取数据。这样的事情似乎有效:
ngOnInit(): void {
let idx = this.activatedRoute.pathFromRoot.length - 1;
while(this.sharedData == null && idx > 0){
this.sub = this.activatedRoute.pathFromRoot[idx].data.subscribe(subData => {
if(subData.id)
this.sharedData = subData;
console.log('shared data', this.sharedData);
});
idx--;
}
}
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'users',
loadChildren: 'app/documents/documents.module#DocumentsModule',
resolve : {
data: DataResolver
}
{
])
],
exports: [
RouterModule
]
})
export class UsersManagementRoutingModule {
}
@Injectable()
export class DataResolverimplements Resolve<Data> {
resolve() {
return this.serice.getData();
}
}
如果您现在在这里结束,check out 路由器配置选项 paramsInheritanceStrategy
。它允许您优化 'how the router merges parameters, data, and resolved data from parent to child routes.' 我有一些未发送到延迟加载模块的已解决数据,将参数设置为 'always' 为我解决了这个问题。
我的 Angular 应用程序的一个模块有以下路由路径:
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'documents',
data: { myObject: MyConstants.OPTION_ONE },
children: [
{
path: ':ID_DOC',
children: [
{ path: 'edit', component: EditDocumentComponent },
{ path: '', component: DocumentDetailsComponent },
]
},
{ path: 'add', component: AddDocumentComponent },
{ path: '', component: DocumentsListComponent }
]
}
])
],
exports: [
RouterModule
]
})
export class DocumentsManagementRoutingModule {
}
如您所见,我使用 data
属性 将一些数据传递到 "documents" 中的每个路径,因此我可以从路由路径中声明的任何组件中获取它:
例如,这是我在 DocumentDetailsComponent
中获取数据的方式:
export class DocumentDetailsComponent implements OnDestroy {
private obsData: Subscription;
private option: any;
constructor(private route: ActivatedRoute) {
this.obsData = this.route.data.subscribe(data => {
this.option = data['myObject'];
});
}
ngOnDestroy(): void {
this.obsData.unsubscribe();
}
}
现在我改变了整个应用程序的路由结构,我从其他模块调用上面的模块,在延迟加载中,使用 loadChildren
属性。我以同样的方式传递数据:
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'users',
loadChildren: 'app/documents/documents.module#DocumentsModule',
data: { myObject: MyConstants.OPTION_ONE }},
{
path: ':ID_USER',
children: [
{ path: 'edit', component: EditUserComponent },
{ path: '', component: UserDetailsComponent },
]
},
{ path: 'add', component: AddUserComponent },
{ path: '', component: UserListComponent }
])
],
exports: [
RouterModule
]
})
export class UsersManagementRoutingModule {
}
我对调用 DocumentsManagementRoutingModule
的所有其他模块也做了同样的事情,将 myObject
属性 更改为 MyConstants.OPTION_TWO
、MyConstants.OPTION_THREE
等等,根据我的需要。
那么,由于不知道调用我的懒加载模块的模块及其相关路径,如何从调用模块获取data
属性?
为什么不使用服务在模块或任何组件之间共享数据。您可以在主模块提供程序中导入此服务,因此可以在所有其他模块(延迟加载模块)中使用并共享数据。
该服务可以具有设置和获取值的功能,因此您可以在服务中使用这些功能来获取所需的数据
我想我可能明白问题在问什么了。
问题
这是@smartmouse提供的plunker的路由图。
- home
- shop
- contact
- map
- about
home
路由配置中配置了一个 data
对象。直接子路由可以访问这个数据对象。问题是,非直接子 map
想要访问 data
对象,但显然,它不能。
而且我们可以知道@smartmouse 想要更进一步——嵌套的非直接子路由可以访问来自祖先的数据。
为什么不能?
查看我修改过的plunker。 https://plnkr.co/edit/FA7mGmspUXHhU8YvgDpT
你可以看到我为contact
定义了一个额外的子组件DefaultComponent
。表明它是路由contact
的直接和默认子路由,可以解释为它也是上级路由home
的直接子路由。因此,它可以访问 data
对象。
解决方案
再看看我提供的插件
NOTE: The Angular packages I'm using is v4.3.0
方法 #1 -- 查询参数
我在 home.component.ts
中为 contact
路由定义了一些查询参数。你可以看看如何使用它。
优点:
- 您可以跨任何级别的路由访问查询参数。
- 与延迟加载模块配合得很好
缺点:
您不能在路由配置中定义查询参数。
但是你可以使用一些路由生命周期钩子来为目标祖先路由定义它们
方法 #2 -- 服务
在应用程序的 顶层 上定义数据共享服务作为单例模式。另外,使用一些实用程序来防止它被启动两次。然后你可以将一些数据放入其中,并在任何地方检索它。
优点:
- 通过 DI 全局可见;
- 与延迟加载模块配合得很好
缺点:
- 您无法更新路由配置中的数据。
- 您必须在其他地方定义数据。如果你不能控制它的来源,那可能是个问题。
方法 #3 -- 路由解析
有人可能会发现我还在 plunker 中定义了 resolve
示例代码。这是为了表明它与路由配置中的 data
具有相同的行为,除了它实际上是用于动态数据检索。
https://vsavkin.com/angular-router-understanding-router-state-7b5b95a12eab#5400
The data property is used for passing a fixed object to an activated route. It does not change throughout the lifetime of the application. The resolve property is used for dynamic data.
以@smartmouse的plunkr为例
我们在 'home' 路由配置中定义了 data
。我们可以在ContactModule
中为contact的默认路由定义一个数据解析器,代理从上级路由传过来的数据。然后它的所有直接子路由都可以访问 resolved 数据对象。
优点:
- 适用于任何级别的嵌套路由
- 与延迟加载模块配合得很好
缺点:
- 您可能必须在其子路由想要访问该数据的每个父路由中声明解析 属性。这是一种肮脏的工作。
目前还没有完美通用的解决方案,常用Angular。有人应该权衡利弊,选择合适的。
您可以使用activatedRoute.pathFromRoot遍历父路由,并从最近的可用祖先获取数据。这样的事情似乎有效:
ngOnInit(): void {
let idx = this.activatedRoute.pathFromRoot.length - 1;
while(this.sharedData == null && idx > 0){
this.sub = this.activatedRoute.pathFromRoot[idx].data.subscribe(subData => {
if(subData.id)
this.sharedData = subData;
console.log('shared data', this.sharedData);
});
idx--;
}
}
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'users',
loadChildren: 'app/documents/documents.module#DocumentsModule',
resolve : {
data: DataResolver
}
{
])
],
exports: [
RouterModule
]
})
export class UsersManagementRoutingModule {
}
@Injectable()
export class DataResolverimplements Resolve<Data> {
resolve() {
return this.serice.getData();
}
}
如果您现在在这里结束,check out 路由器配置选项 paramsInheritanceStrategy
。它允许您优化 'how the router merges parameters, data, and resolved data from parent to child routes.' 我有一些未发送到延迟加载模块的已解决数据,将参数设置为 'always' 为我解决了这个问题。