Can anyone please clarify to me how should I structure multiple nested feature modules hierarchy with .forRoot() calls?
For example what if I have modules like this:
As forRoot
intended only to provide singleton services, you can "re-provide" them explicitly in SharedModule
:
@NgModule({})
class SharedModule {
static forRoot() {
return {
ngModule: SharedModule,
providers: [
AuthService,
FeatureModuleA.forRoot().providers,
FeatureModuleB.forRoot().providers,
],
}
}
}
This way all the services will be provided by the SharedModule
itself (not by respective sub-module) but it seems that it doesn't matter. Maybe someone can argue though...
Note, that FeatureModuleA
can also "re-provide" singleton services from its sub-modules it similar manner.
As mentioned above, lazy loaded modules are important to consider because a shared service could be used in a lazy loaded module, but if that service was already used and instantiated by another module, then there will be two instances hence the need for the singleton pattern. An AuthService is a great example here - you don't want to have one instance of the service with an unauthenticated user while another has "the same" user authenticated.
New to Angular 6 there is a new way to register a provider as a singleton. Inside the @Injectable() decorator for a service, use the providedIn attribute. Set its value to 'root'. Then you won't need to add it to the providers list of the root module, or in this case you could also set it to your SharedModule like this:
@Injectable({
providedIn: SharedModule // or 'root' for singleton
})
export class AuthService {
...
Generally forRoot
is used to add application/singleton services.
@NgModule({
providers: [ /* DONT ADD HERE */ ]
})
class SharedModule {
static forRoot() {
return {
ngModule: SharedModule,
providers: [ AuthService ]
}
}
}
The reasoning is that if you add the AuthService
to the providers
in the @NgModule
, it's possible for more than one to be created if you import the SharedModule
into other modules.
I'm not 100% clear on whether the service would be created when the SharedModule
is imported into an eagerly loaded module, but the explanation that the docs mentioned was in regards to lazily loaded modules. When you lazily load a module, all the providers will get created.
For this reason, we add a (by convention) forRoot
method to signify that the method should only be called for the root (app) module, while for other module it should just be imported normally
@NgModule({
imports: [SharedModule]
})
class FeatureModule {}
@NgModule({
imports: [SharedModule.forRoot()]
})
class AppModule {}