Angular router: как передать данные в ленивый модуль загрузки?
У меня есть следующие пути маршрутизации для модуля моего приложения 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
для передачи некоторых данных каждому пути в "документах", поэтому я могу получить его из любого из компонентов, объявленных в маршрутах маршрутизации:
Например, вот как я получаю данные в 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
из модуля вызывающего абонента?
Ответы
Ответ 1
Вы можете перемещаться по родительским маршрутам с помощью activateRoute.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--;
}
}
https://plnkr.co/edit/K5Rb1ZvTvSQNM6tOLeFp
Ответ 2
Думаю, я понимаю, о чем спрашивает вопрос.
Проблема
Вот график маршрутизации предоставляемой plunker @smartmouse.
- home
- shop
- contact
- map
- about
В конфигурации маршрута home
настроен объект data
. Прямые дочерние маршруты могут обращаться к этому объекту данных. Проблема заключается в том, что непрямой дочерний элемент map
хочет получить доступ к объекту data
, но, по-видимому, он не может.
И мы можем знать, что @smartmouse хочет нажать, что еще дальше - вложенные не прямые прямые маршруты могут обращаться к данным от предка.
Почему это не может?
См. плункер, который я изменил. https://plnkr.co/edit/FA7mGmspUXHhU8YvgDpT
Вы можете видеть, что я определяю дополнительный дочерний компонент DefaultComponent
для contact
. Он показывает, что это прямой и по умолчанию ребенок маршрута contact
, который может быть интерпретирован, так как он также является прямым ребенком высшего маршрута home
. Таким образом, он может получить доступ к объекту data
.
Решение
Посмотрите на плункер, предоставленный мной снова.
ПРИМЕЧАНИЕ. Пакеты Angular, которые я использую, - v4.3.0
Подход №1 - параметры запроса
Я определяю некоторые параметры запроса в home.component.ts
для маршрута contact
. Вы можете увидеть, как его использовать.
Pros
- вы можете получить доступ к параметрам запроса на любом уровне маршрутов.
- хорошо работает с модулями lazyload
против
-
вы не можете определить параметры запроса в конфигурации маршрута.
Но вы можете использовать некоторые крючки жизненного цикла маршрута, чтобы определить их для маршрутов целевых предков.
Подход №2 - сервис
Определите службу обмена данными на верхнем уровне приложения, играющего в качестве шаблона Singleton. Кроме того, используйте некоторые утилиты, чтобы предотвратить его запуск дважды. Затем вы можете поместить в него некоторые данные и получить их в любом месте.
Pros
- глобально видимый через DI;
- хорошо работает с модулями lazyload
против
- вы не можете обновлять данные в конфигурации маршрута.
- вам нужно определить данные в другом месте. Если вы не можете контролировать источник, это может быть проблемой.
Подход № 3 - разрешение маршрута
Кто-то может узнать, что я также определил код образца resolve
в plunker. Он показывает, что он имеет такое же поведение, как data
в конфигурации маршрута, за исключением того, что он действительно предназначен для получения динамических данных.
https://vsavkin.com/angular-router-understanding-router-state-7b5b95a12eab#5400
Свойство data используется для передачи фиксированного объекта в активированный маршрут. Он не меняется на протяжении всего срока службы приложения. Свойство resol используется для динамических данных.
Возьмите @smartmouse plunkr в качестве примера.
У нас есть data
, определенный в конфигурации "home" route. Мы можем определить преобразователь данных в ContactModule
для маршрута контакта по умолчанию и проксировать данные, переданные с более высокого маршрута. Затем все его прямые дочерние маршруты могут получить доступ к разрешенному объекту данных.
Pros
- хорошо работает с любым уровнем вложенных маршрутов.
- хорошо работает с модулями lazyload
против
- Возможно, вам придется объявить это свойство разрешения в каждом родительском маршруте, чьи дочерние маршруты хотят получить доступ к этим данным. Это своего рода грязная работа.
На сегодняшний день нет идеального и универсального решения с общим использованием Angular. Кто-то должен взвесить плюсы и минусы и выбрать правильный.
Ответ 3
@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();
}
}
Ответ 4
Почему вы не используете службу для обмена данными между модулями или любыми компонентами. Вы можете импортировать эту услугу у поставщика основного модуля и, следовательно, ее можно использовать во всех других модулях (ленивый модуль загрузки) и обмениваться данными.
Служба может иметь функции для установки и получения значений и, следовательно, вы можете использовать эти функции в службах для получения необходимых данных.