Dependency injection in Angular 2 can quickly get confusing if you’re trying to really understand what’s going on “under the hood”. Even researching it myself, I’ll be the first to admit I don’t have the entire picture clearly mapped out, but I wanted to share what I’ve learned about dependency injection in Angular 2 in hopes that it will help you understand a little better yourself.
The entire concept of dependency injection in the framework consists of three things.
- Injector - The injector object that exposes APIs to us to create instances of dependencies.
- Provider - A provider is like a recipe that tells the injector how to create an instance of a dependency. A provider takes a token and maps that to a factory function that creates an object.
- Dependency - A dependency is the type of which an object should be created.
The above might be a confusing on the surface, but it may be a little easier to represent in code.
In the scenario above,
this.myService is the dependency, the injector instance is imported and passed into the constructor,
which we access with
this.injector, and the
MyService class is the provider. Angular usually does this for us (we’ll get to that
in just a minute), but writing it this way can better explain the diagram and dependency injection description above.
The dependency is passed in (usually) as a singleton instance, and, if this is the first time the dependency is being fetched by the injector, it will instantiate that singleton. Otherwise, it will fetch the the existing object.
What Angular does
Normally, you’ll declare providers in an
NgModule like so:
The token used inside the array,
MyProvider is actually an alias for
useClass makes it seem like you can give different objects for a provider right? Well, that’s exactly right!
Here are some other keys you can use:
This would be used for aliasing one provider to another. An example from the Angular docs uses a hypothetical scenario in which
OldLogger, cannot be deleted, but when it’s used we actually want it to call
NewLogger instead. As long as the
two providers have the same interface, the new provider will be called when the old one is called, hence delegating responsibility
to the new provider.
If you want to use a function, string, etc. as a provider, you can do that with this key. A really good use case I’ve seen for this
is passing around an API key. In your
AppModule you could create a provider using the
Then, to inject the key into a service, you can do the following.
If we need to create the provider value dynamically at the last possible second for whatever reason, we can use a factory provider to do so.
In the example above, we’re declaring the factory as a function and passing in the dependencies. Because of this, we need to also pass the dependencies into the provider declaration.
I hope this has helped in your understanding of dependency injection in Angular 2. You can find most of this (and more) in the Angular documentation, and do let me know if you have any questions or comments. Happy coding!