Reputation: 167
I currently have an issue with lazy laoded modules and services which are providedIn
this lazy-loaded module.
I have a folder structure looking like this:
app
-> featureModule1 (lazy loaded)
-> featureModule2 (lazy loaded)
-->services
--->service1.ts
I want this service1.ts only be available in featureModule2. So i included @Injectable
// service.ts
@Injectable({
providedIn: featureModule2
})
export class service1 { /* some logic */ }
When i try to route to this lazy loaded module i get an console error:
// console
ERROR Error: Uncaught (in promise): ReferenceError: Cannot access 'featureModule2' before initialization
ReferenceError: Cannot access 'featureModule2' before initialization
My current lazy load route looks like this:
// app-routing.module.ts
const routes: Routes = [
{path: '', redirectTo: '', pathMatch: 'full'},
{ path: 'feature1', loadChildren: () => import('./feature1/feature1.module').then(m => m.featureModule1) },
{ path: 'feature2', loadChildren: () => import('./feature2/feature2.module').then(m => m.featureModule2) }
];
I tried to provide it in the module:
// featureModule1
@NgModule({
declarations: [
featureComponent
],
imports: [
...
],
providers: [
service1
]
})
That doesn't work.
And i tried to import the service1.ts directly a component (featureComponent
).
// featureComponent
import { service1 } from '../featureModule2/services/service1.service';
@Component({
...
})
export class featureComponent {
constructor(private service1: service1) { }
ngOnInit(): void {
this.service1.init();
}
}
This approach lead to the same error message.
The only way to get around this issue at the moment is to create a "wrapper" module which imports all other modules with @Injectable
services.
Is there a different way for this problem? The services in each module should not be injected in root
or any
because they should only be available in each featureModule.
Upvotes: 4
Views: 3134
Reputation: 3727
When we configure a service like this:
@Injectable({
providedIn: featureModule2
})
export class TestService {
}
It means that TestService
won't be available to applications unless they import featureModule2.
Since featureModule2 is a lazy loaded module, you definitely not want to specify this in app module imports and hence you will need to either use
@Injectable({
providedIn: 'any'
})
export class TestService {
}
or
@Injectable({
providedIn: 'root'
})
export class TestService {
}
The different between above two is that when we use 'root
there will be a single instance of that service throught the app. In case of 'any
' for lazily loaded module there will be a new instance of that service and for eagerly loaded module it will act as a singleton.
Upvotes: 1
Reputation: 32517
You just have to declare it in providers
section and it will work. I have used useFactory
provider variant in order to clearly show that it is used in order to perform injection and angular is not simply new LazyService
just in place. I will work with providers:[LazyService]
as well (which is a 'class provider' I belive, equal to useClass:LazyService
)
In lazy module
import {
CustomerListComponent,
LazyService
} from './customer-list/customer-list.component';
@NgModule({
imports: [CommonModule, CustomersRoutingModule],
declarations: [CustomerListComponent],
providers: [
{
provide: LazyService,
useFactory: () => new LazyService('proofThatItIsFromPRoviders')
}
]
})
export class CustomersModule {}
in lazy component from the same module ("printsLazy service works proofThatItIsFromPRoviders")
export class LazyService {
constructor(private test: string) {}
public say() {
console.log('Lazy service works', this.test);
}
}
@Component({
selector: 'app-customer-list',
templateUrl: './customer-list.component.html',
styleUrls: ['./customer-list.component.css']
})
export class CustomerListComponent implements OnInit {
constructor(private lazy: LazyService) {}
ngOnInit() {
this.lazy.say();
}
}
injection in different module fails
@Component({
selector: 'app-order-list',
templateUrl: './order-list.component.html',
styleUrls: ['./order-list.component.css']
})
export class OrderListComponent implements OnInit {
constructor(private lazy:LazyService) { }
ngOnInit() {
this.lazy.say();
}
}
Working example here https://stackblitz.com/edit/angular-s5xxnb-j9ch1z?file=src%2Fapp%2Forders%2Forder-list%2Forder-list.component.ts
Upvotes: 1