What would be the way to go if I wanted to inject a non-singleton service into another non-singleton service in Angular?
Let's say I have a ComponentA
which uses a ServiceA
like this
@component({
selector: "componentA",
providers: [ServiceA]
})
export class ComponentA {
constructor(private serviceA: ServiceA) {}
}
and now, ServiceA
also depends on ServiceB
, so I need to inject it
@Injectable()
export class ServiceA {
constructor(private serviceB: ServiceB) {}
}
How/where would I declare my ServiceB
? In the module? In that case would that be a singleton?
If I add it to the providers in ComponentA
it works fine, but then I need to know in ComponentA
that ServiceA
depends on ServiceB
, which doesn't seem fine to me.
Thanks!
Angular provides the ability for you to inject a service into a component to give that component access to the service. The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency.
In this case, service is a non-singleton nature. It will create multiple instances of a service. Every time a new instance of provided service will be created when a component is used inside another component. Service is being destroyed along with the component.
There are multiple ways to prevent this: Use the providedIn syntax instead of registering the service in the module. Separate your services into their own module. Define forRoot() and forChild() methods in the module.
By default, this decorator has a providedIn property, which creates a provider for the service. In this case, providedIn: 'root' specifies that Angular should provide the service in the root injector.
Roughly speaking, unless you have the providedIn
options in the @Injectable()
, Angular will not treat the service as a singleton. You can refer to the docs for details on how that works: https://angular.io/api/core/Injectable#providedin
The issue that you will run into, is that if you simply do:
@Injectable()
export class ServiceB {
constructor() {}
}
It will throw an error when trying to inject ServiceB into ServiceA because it has no provider. Now normally, to resolve this, you would add { providedIn: 'root' }
to ServiceB's @Injectable()
. This will create service B as an application-wide singleton service.
When you use @Component( { providers: [] } )
that will create an instance just for that component. But you can't do that for a service.
You may ask, why doesn't @Injectable()
have a providers
option like @Component()
does? The Angular team doesn't want to do this for a number of reasons, see this github issue for more info https://github.com/angular/angular/issues/5622
TLDR:
To provide you with something to solve this problem, you can keep it simple and avoid using Angular's DI altogether if you want control over what instances you use, you can just do it yourself:
@Injectable()
export class ServiceA {
constructor(private serviceB: ServiceB = new ServiceB()) {}
}
or
@NgModule()
and/or @Component()
providers
arrays,@Injectable( { providedIn: <something> } )
(https://angular.io/api/core/Injectable#providedin)Edit: as suggested by @minigeek, using providedIn
you can use any
to make each lazy module get it's own instance of the service.
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