Angular2 - inject into @Injectable

2020-04-08 07:35发布

问题:

I have an Angular2 app with a service that is used for getting a data from an API. Following this example, I want to create a separate file which should contain some configuration data. My problem is that my service has an @Injectable() decorator and I'm not sure if I can pass it a provide array in the metadata in which I will inject the configuration as shown in the tutorial. Anybody ever faced such a problem is welcome to share his solution :)

回答1:

In fact, Angular2 leverages hierarchical injectors and injectors are linked to components. In short you can define providers only on components (providers property) or at application level (bootstrap function).

Regarding services, they will be able to use providers that are visible for the component that initiated the call but you can't define providers at their levels.

Here is a sample:

Application
     |
AppComponent
     |
ChildComponent
  getData()     --- Service1 --- Service2

In such application, we have three injectors:

  • The application injector that can be configured using the second parameter of the bootstrap function
  • The AppComponent injector that can be configured using the providers attribute of this component. It can "see" elements defined in the application injector. This means if a provider isn't found in this provider, it will be automatically look for into this parent injector. If not found in the latter, a "provider not found" error will be thrown.
  • The ChildComponent injector that will follow the same rules than the AppComponent one. To inject elements involved in the injection chain executed forr the component, providers will be looked for first in this injector, then in the AppComponent one and finally in the application one.

This means that when trying to inject the Service1 into the ChildComponent constructor, Angular2 will look into the ChildComponent injector, then into the AppComponent one and finally into the application one.

Since Service2 needs to be injected into Service1, the same resolution processing will be done: ChildComponent injector, AppComponent one and application one.

This means that both Service1 and Service2 can be specified at each level according to your needs using the providers attribute for components and the second parameter of the bootstrap function for the application injector.

This answer could help you:

  • What's the best way to inject one service into another in angular 2 (Beta)?


回答2:

It is a bit strange, but only components can configure dependency injection in Angular (well, and bootstrap(), but that is essentially the same as the root component). I.e., only components can specify providers.

As @Thierry mentions in his answer, each component in the component tree will get an associated "injector" if the component has a providers array specified. We can think of this like an injector tree, that is (normally much) sparser than the component tree. When a dependency needs to be resolved, this injector tree is consulted. The first injector that can satisfy the dependency does so. The injector tree is walked up, toward the root component/injector.

So, in order for your service to inject a configuration object dependency, that config object first has to be registered with an injector. I.e., in a component's providers array, call
provide(stringToken or OpaqueToken, {useValue: MyConfigObject} )
This registration must occur somewhere at or above the component where you want to use/inject your service.

Your service should then be able to @Inject the registered config object, because it will find it in the injector tree.

Note, since only components can configure providers, the @Injectable() decorator does not support any configuration options, so a providers array is not supported.



回答3:

This is not supported. For services the providers need to be added to bootstrap(AppComponent, [..., Service, ServiceDependency1, ...])

See also https://github.com/angular/angular/issues/5622