Dead Simple Dependency Injection in Angular 2
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.
Errr, what?
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
They key 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:
useExisting
This would be used for aliasing one provider to another. An example from the Angular docs uses a hypothetical scenario in which
an interface, 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.
useValue
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 useValue
key.
Then, to inject the key into a service, you can do the following.
useFactory
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.
Conclusion
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!