The new dependency injection system in Angular comes with a feature called “Multi Providers” that basically enable us, the consumer of the platform, to hook into certain operations and plug in custom functionality we might need in our application use case. We’re going to discuss what they look like, how they work and how Angular itself takes advantage of them to keep the platform flexible and extendible.
Recap: What is a provider?
If you’ve read our article on Dependency Injection in Angular you can probably skip this section, as you’re familiar with the provider terminology, how they work, and how they relate to actual dependencies being injected. If you haven’t read about providers yet, here’s a quick recap.
A provider is an instruction that describes how an object for a certain token is created.
Quick example: In an Angular component we might have a
DataService dependency, which we can ask for like this:
We import the type of the dependency we’re asking for, and annotate our dependency argument with it in our component’s constructor. Angular knows how to create and inject an object of type
DataService, if we configure a provider for it. This can happen either on the application module, that bootstrap our app, or in the component itself (both ways have different implications on the dependency’s life cycle and availability).
In fact, there’s a shorthand syntax we can use if the instruction is
useClass and the value of it the same as the token, which is the case in this particular provider:
Now, whenever we ask for a dependency of type
DataService, Angular knows how to create an object for it.
Understanding Multi Providers
With multi providers, we can basically provide multiple dependencies for a single token. Let’s see what that looks like. The following code manually creates an injector with multi providers:
Note: We usually don’t create injectors manually when building Angular applications since the platform takes care of that for us. This is really just for demonstration purposes.
A token can be either a string or a type. We use a string, because we don’t want to create classes to represent a string value in DI. However, to provide better error messages in case something goes wrong, we can create our string token using
OpaqueToken. We don’t have to worry about this too much now. The interesting part is where we’re registering our providers using the
multi: true option.
multi: true tells Angular that the provider is a multi provider. As mentioned earlier, with multi providers, we can provide multiple values for a single token in DI. That’s exactly what we’re doing. We have two providers, both have the same token but they provide different values. If we ask for a dependency for that token, what we get is a list of all registered and provided values.
Okay understood, but why?
Alright, fine. We can provide multiple values for a single token. But why in hell would we do this? Where is this useful? Good question!
Usually, when we register multiple providers with the same token, the last one wins. For example, if we take a look at the following code, only
TurboEngine gets injected because it’s provider has been registered at last:
This means, with multi providers we can basically extend the thing that is being injected for a particular token. Angular uses this mechanism to provide pluggable hooks.
One of these hooks for example are validators. When creating a validator, we need to add it to the
NG_VALIDATORS multi provider, so Angular picks it up when needed
Multi providers also can’t be mixed with normal providers. This makes sense since we either extend or override a provider for a token.
Other Multi Providers
The Angular platform comes with a couple more multi providers that we can extend with our custom code. At the time of writing these were
NG_VALIDATORS- Interface that can be implemented by classes that can act as validators
NG_ASYNC_VALIDATORS- Token that can be implemented by classes that can act as async validators
Multi providers are a very nice feature to implement pluggable interface that can be extended from the outside world. The only “downside” I can see is that multi providers only as powerful as what the platform provides.
NG_ASYNC_VALIDATORS are implemented right into the platform, which is the only reason we can take advantage of those particular multi providers. There’s no way we can introduce our own custom multi providers (with a specific token) that influences what the platform does, but maybe this is also not needed.
Angular Master Class at Shopware
Join our upcoming public training!Get a ticket →
Get updates on new articles and trainings.
Join over 1400 other developers who get our content first.
RxJS Master Class and courseware updates
If you've been following us for a while, you're quite aware that we're always striving to provide up-to-date and high-quality...
Advanced caching with RxJS
When building web applications, performance should always be a top priority. One very efficient way to optimize the performance of...
Custom Overlays with Angular's CDK - Part 2
In this follow-up post we demonstrate how to use Angular's CDK to build a custom overlay that looks and feels...
Custom Overlays with Angular's CDK
The Angular Material CDK provides us with tools to build awesome and high-quality Angular components without adopting the Material Design...
Easy Dialogs with Angular Material
Building modals and dialogs isn't easy - if we do it ourselves. Angular Material comes with a powerful dialog service...
A web animations deep dive with Angular
Angular comes with a built-in animation system that lets us create powerful animations based on the Web Animations API. In...
You might also be interested in
Exploring Angular 2 - Article SeriesRead more