Sharing the Same Dependency Injection Tree
So far our problem is that we are creating two instances of the same services in different levels of the DI tree. The instance created in the lower branch of the tree is shadowing the one defined at the root level. The solution? To avoid creating a second instance in a lower level of the DI tree for the lazy loaded module and only use the service instance registered at the root of the tree.
To accomplish that, we need to modify the definition of the SharedModule and instead of defining our service in the providers property, we need to create a static method called forRoot that exports the service along with the module itself.
app/shared/shared.module.ts
1
import { NgModule, ModuleWithProviders } from '@angular/core';
2
import { CounterService } from './counter.service';
3
4
@NgModule({})
5
export class SharedModule {
6
static forRoot(): ModuleWithProviders {
7
return {
8
ngModule: SharedModule,
9
providers: [CounterService]
10
};
11
}
12
}
Copied!
With this setup, we can import this module in our root module AppModule calling the forRoot method to register the module and the service.
app/app.module.ts
1
...
2
import { SharedModule } from './shared/shared.module';
3
4
@NgModule({
5
imports: [
6
SharedModule.forRoot(),
7
...
8
],
9
...
10
})
11
export class AppModule {}
Copied!
We should only call forRoot in the root application module and no where else. This ensures that only a single instance of your service exists at the root level. Calling forRoot in another module can register the service again in a different level of the DI tree.
Since SharedModule only consists of a service that Angular registers in the root app injector, we do not need to import it in LazyModule. This is because the lazy loaded module will already have access to services defined at the root level.
This time, whenever we change the value of the counter property, this value is shared between the EagerComponent and the LazyComponent proving that we are using the same instance of the CounterService.
However it is very likely that we may have a component, pipe or directive defined in SharedModule that we'll need in another module. Take the following for example.
app/shared/shared.module.ts
1
import { NgModule, ModuleWithProviders } from '@angular/core';
2
import { CounterService } from './counter.service';
3
4
import { HighlightDirective } from './highlight.directive';
5
6
@NgModule({
7
declarations: [HighlightDirective],
8
exports: [ HighlightDirective ]
9
})
10
export class SharedModule {
11
static forRoot(): ModuleWithProviders {
12
return {
13
ngModule: SharedModule,
14
providers: [CounterService]
15
};
16
}
17
}
Copied!
In here, we declare and export HighlightDirective so other modules that import SharedModule can use it in their templates. This means we can just import the module in LazyModule normally.
app/lazy/lazy.module.ts
1
import { NgModule } from '@angular/core';
2
3
import { SharedModule } from '../shared/shared.module';
4
5
import { LazyComponent } from './lazy.component';
6
import { routing } from './lazy.routing';
7
8
@NgModule({
9
imports: [
10
SharedModule,
11
routing
12
],
13
declarations: [LazyComponent]
14
})
15
export class LazyModule {}
Copied!
Now we can use this directive within LazyModule without creating another instance of CounterService.
Last modified 2yr ago
Copy link