Reputation: 812
I want to declare a string via a useValue
provider, for use by components in a "reusable" module. I expect that I should be able to override the same "key" with different values in several top-level modules, and the reusable components will be provided the nearest-module's value based on the scope hierarchy.
An example use case for this is a CrudModule, which speaks API basics (create, list, etc).
To keep your code DRY (without lots of inheritance), you might simply provide the CRUD resource name via dependency injection (e.g. "users", "teams", "projects", for the routes v1/users
, v1/teams
, v1/projects
). In this example, you might organize your code base into the modules UsersModule
, TeamsModule
, ProjectsModule
, CrudModule
.
Here's a Plunker demonstrating what I get vs my expectations. This uses a simpler (contrived) example with Dogs vs Cats, trying to provide a string "dog"
vs "cat"
from each module:
https://embed.plnkr.co/pNRpj6/
In contrast, if you do the same thing, but put the providers on components, it works as expected:
https://embed.plnkr.co/BsgwmR/
For my app design, I don't think I can get the behavior I need by putting my "polymorphic providers" on Components. On top of that, I think it's a much cleaner and better design to put these on my Modules.
Am I doing something wrong in my first example (providers on Modules)? Is there something I'm missing that this is the expected behavior?
Upvotes: 1
Views: 1651
Reputation: 214175
Providers added to modules that you are importing to root module are added to the main injector AppModuleInjector
When two imported modules, loaded at the same time, list a provider with the same token, the second module's provider "wins".
When Angular looks to inject a service for that token, it creates and delivers the instance created by the second provider.
Every class that injects this service gets the instance created by the second provider. Even classes declared within the first module get the instance created by the second provider.
If Module A provides a service for token 'X' and imports a module B that also provides a service for token 'X', then Module A's service definition "wins".
The service provided by the root AppModule takes precedence over services provided by imported modules. The AppModule always wins.
There are two options to restrict service scope:
1) If you must load the module eagerly than provide animal
within component providers
array
2) Load the module lazily if you can. Angular gives a lazy-loaded module its own child injector.
Upvotes: 3