Как использовать.forRoot() в иерархии модулей функций
Может ли кто-нибудь объяснить мне, как я должен структурировать иерархию нескольких вложенных функциональных модулей с помощью вызовов.forRoot()?
Например, что если у меня есть такие модули:
- MainModule
- SharedModule
- FeatureModuleA
- FeatureModuleA1
- FeatureModuleA2
- FeatureModuleB
Все функциональные модули имеют статические функции.forRoot().
Как мне определить FeatureModuleA с каким-то образом "передать" функции.forRoot()?
@NgModule({
imports: [
//- I can use .forRoot() calls here but this module not the root module
//- I don't need to import sub-modules here, FeatureA only a wrapper
//FeatureModuleA1.forRoot(), //WRONG!
//FeatureModuleA2.forRoot(), //WRONG!
],
exports: [
//I cannot use .forRoot() calls here
FeatureModuleA1,
FeatureModuleA2
]
})
class FeatureModuleA {
static forRoot(): ModuleWithProviders {
return {
//At this point I can set any other class than FeatureModuleA for root
//So lets create a FeatureRootModuleA class: see below!
ngModule: FeatureModuleA //should be: FeatureRootModuleA
};
}
}
Я могу создать другой класс для использования root, а затем установить его в функции forRoot () FeatureModuleA:
@NgModule({
imports: [
//Still don't need any sub module within this feature module
]
exports: [
//Still cannot use .forRoot() calls but still need to export them for root module too:
FeatureModuleA1,
FeatureModuleA2
]
})
class FeatureRootModuleA { }
Но как я могу "перевести" вызовы.forRoot() в этот специальный ModuleClass?
Как я вижу, мне нужно импортировать все подмодули непосредственно в мой корневой MainModule и вызывать.forRoot() для каждого там:
@NgModule({
imports: [
FeatureModuleA1.forRoot(),
FeatureModuleA2.forRoot(),
FeatureModuleA.forRoot(),
SharedModule.forRoot()
]
})
class MainModule { }
Я прав? Перед тем, как ответить, посмотрите этот файл: https://github.com/angular/material2/blob/master/src/lib/module.ts
Насколько мне известно, этот репо поддерживается официальной угловой командой. Таким образом, они решают вышеупомянутое, просто импортируя все вызовы.forRoot() в специальном модуле MaterialRootModule. Я не очень понимаю, как это будет применяться для моего собственного корневого модуля? Что на самом деле означает root и .forRoot? Это относится к пакету, а не к реальному веб-проекту?
3 ответа
В общем-то forRoot
используется для добавления приложений / одноэлементных сервисов.
@NgModule({
providers: [ /* DONT ADD HERE */ ]
})
class SharedModule {
static forRoot() {
return {
ngModule: SharedModule,
providers: [ AuthService ]
}
}
}
Причина заключается в том, что если вы добавите AuthService
к providers
в @NgModule
возможно создание нескольких, если вы импортируете SharedModule
в другие модули.
Я не уверен на 100%, будет ли создан сервис, когда SharedModule
импортируется в загруженный модуль, но объяснение, что упомянутые документы были в отношении лениво загруженных модулей. Когда вы лениво загружаете модуль, все провайдеры будут созданы.
По этой причине мы добавляем (по соглашению) forRoot
метод для обозначения того, что метод должен вызываться только для модуля root (app), в то время как для другого модуля он должен быть просто импортирован нормально
@NgModule({
imports: [SharedModule]
})
class FeatureModule {}
@NgModule({
imports: [SharedModule.forRoot()]
})
class AppModule {}
Как forRoot
предназначены только для предоставления одноразовых услуг, вы можете явно "повторно" предоставить их в SharedModule
:
@NgModule({})
class SharedModule {
static forRoot() {
return {
ngModule: SharedModule,
providers: [
AuthService,
FeatureModuleA.forRoot().providers,
FeatureModuleB.forRoot().providers,
],
}
}
}
Таким образом, все услуги будут предоставлены SharedModule
сам (не соответствующим подмодулем), но кажется, что это не имеет значения. Может быть, кто-то может поспорить, хотя...
Обратите внимание, что FeatureModuleA
может также "повторно" предоставлять синглтон-сервисы из своих подмодулей аналогичным образом.
Как упомянуто выше, важно загружать модули с отложенной загрузкой, поскольку совместно используемую службу можно использовать в модуле с отложенной загрузкой, но если эта служба уже использовалась и создавалась другим модулем, тогда будет два экземпляра, следовательно, потребуется шаблон синглтона., Отличным примером здесь является AuthService - вы не хотите, чтобы один экземпляр службы был с неаутентифицированным пользователем, в то время как у другого "тот же" пользователь прошел аутентификацию.
В Angular 6 появился новый способ регистрации провайдера в качестве синглтона. Внутри декоратора @Injectable() для сервиса используйте атрибут предусмотрен In. Установите его значение "root". Тогда вам не нужно будет добавлять его в список поставщиков корневого модуля, или в этом случае вы также можете установить его в свой SharedModule следующим образом:
@Injectable({
providedIn: SharedModule // or 'root' for singleton
})
export class AuthService {
...