I've just run into a problem with a lazy-loaded module where parent and child module both require the same service but create an instance each. The declaration is identical for both, that is
import { MyService } from './my.service';
...
@NgModule({
...
providers: [
MyService,
...
]
});
and here's the routing setup
export parentRoutes: Routes = [
{ path: ':id', component: ParentComponent, children: [
{ path: '', component: ParentDetailsComponent },
{ path: 'child', loadChildren: 'app/child.module#ChildModule' },
...
]}
];
which, of course, is then imported in the parent module as
RouterModule.forChild(parentRoutes)
How do I go about this if I wanted to share the same service instance?
Why is it bad if a shared module provides a service to a lazy-loaded module? The lazy loaded scenario causes your app to create a new instance every time, instead of using the singleton. Lazy loading is the best practice of loading expensive resources on-demand.
Lazy loading is the process of loading components, modules, or other assets of a website as they're required. Since Angular creates a SPA (Single Page Application), all of its components are loaded at once. This means that a lot of unnecessary libraries or modules might be loaded as well.
Lazy 1 only has a single component, so it is smaller than Lazy 2 (which contains three components).
Lazy loading modules helps us decrease the startup time. With lazy loading our application does not need to load everything at once, it only needs to load what the user expects to see when the app first loads. Modules that are lazily loaded will only be loaded when the user navigates to their routes.
Using a forRoot
, as mentioned here, is what you need probably. The problem it's meant to solve, is directly related to the problem you are experiencing with lazy loaded modules getting their own service.
It's explained here in Configure core services with forRoot
, but that section doesn't explain about the lazy-loading issue. That is explained with a little warning at the end of Shared Modules
Do not specify app-wide singleton
providers
in a shared module. A lazy loaded module that imports that shared module will make its own copy of the service.
@NgModule({})
class SharedModule {
static forRoot() {
return {
ngModule: SharedModule,
providers: [ MyService ]
};
}
}
@NgModule({
import: [ SharedModule.forRoot() ]
})
class AppModule {}
@NgModule({
imports: [ SharedModule ]
})
class LazyLoadedModule {}
This makes sure that the lazy loaded module doesn't get the service. But whether or not the module is lazy loaded or not, this is the pattern that is recommended for app-wide services. Though it should be noted that if you don't have any lazy loaded module, not using the forRoot
patter, and just importing SharedModule
, it will only be one instance of the service. But this pattern should still recommended to be followed.
I guess I jumped to quick on answering without fully looking at the question. In the question, there is no mention of any shared module. It seems the OP is simply trying to add the service to the @NgModule.providers
in both the app module and the lazy loaded child module.
In this case, simply remove the service from the child module providers
. It is not needed. The one added in the app module is enough for the child to be used.
Just remember that providers
are app wide (except in the problem case this post is about), while declarations
are not.
This should work but still I would suggest you to go with SharedModule concept which contains common services,pipes,directives and components.
Shared/SharedModule
import { NgModule,ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MyService } from './my.service';
@NgModule({
imports: [ CommonModule ],
declarations: [],
exports: [ CommonModule ]
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [ MyService ] //<<<====here
};
}
}
AppModule
import {SharedModule} from './shared/shared.module';
...
@NgModule({
imports:[ BrowserModule,SharedModule.forRoot()], //<<<====here
providers: []
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With