2019-12-02 15:47:19 -05:00
# Dependency providers
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
By configuring providers, you can make services available to the parts of your application that need them.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
A dependency [provider ](guide/glossary#provider ) configures an injector with a [DI token ](guide/glossary#di-token ), which that injector uses to provide the runtime version of a dependency value.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
## Specifying a provider token
If you specify the service class as the provider token, the default behavior is for the injector to instantiate that class with `new` .
In the following example, the `Logger` class provides a `Logger` instance.
2018-05-31 15:02:50 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-logger" >
< / code-example >
2020-10-22 14:16:51 -04:00
You can, however, configure an injector with an alternative provider in order to deliver some other object that provides the needed logging functionality.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
You can configure an injector with a service class, you can provide a substitute class, an object, or a factory function.
2018-05-31 15:02:50 -04:00
2020-10-13 08:57:54 -04:00
{@a token}
{@a injection-token}
## Dependency injection tokens
When you configure an [injector ](guide/glossary#injector ) with a [provider ](guide/glossary#provider ), you are associating that provider with a [dependency injection token ](guide/glossary#di-token ), or DI token.
2021-04-29 12:27:27 -04:00
The injector allows Angular to create a map of any internal dependencies.
2020-10-13 08:57:54 -04:00
The DI token acts as a key to that map.
The dependency value is an instance, and the class type serves as a lookup key.
Here, the injector uses the `HeroService` type as the token for looking up `heroService` .
< code-example path = "dependency-injection/src/app/injector.component.ts" region = "get-hero-service" header = "src/app/injector.component.ts" > < / code-example >
When you define a constructor parameter with the `HeroService` class type, Angular knows to inject the service associated with that `HeroService` class token:
< code-example path = "dependency-injection/src/app/heroes/hero-list.component.ts" region = "ctor-signature" header = "src/app/heroes/hero-list.component.ts" >
< / code-example >
Though classes provide many dependency values, the expanded `provide` object lets you associate different kinds of providers with a DI token.
2018-05-31 15:02:50 -04:00
{@a provide}
2020-10-13 08:57:54 -04:00
## Defining providers
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
The class provider syntax is a shorthand expression that expands into a provider configuration, defined by the [`Provider` interface ](api/core/Provider ).
The following example is the class provider syntax for providing a `Logger` class in the `providers` array.
2018-05-31 15:02:50 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-logger" >
< / code-example >
2020-10-22 14:16:51 -04:00
Angular expands the `providers` value into a full provider object as follows.
2018-05-31 15:02:50 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-3" >
< / code-example >
2021-04-29 12:27:27 -04:00
The expanded provider configuration is an object literal with two properties:
2018-05-31 15:02:50 -04:00
2020-10-13 08:57:54 -04:00
* The `provide` property holds the [token ](#token )
that serves as the key for both locating a dependency value and configuring the injector.
* The second property is a provider definition object, which tells the injector how to create the dependency value.
2018-05-31 15:02:50 -04:00
The provider-definition key can be `useClass` , as in the example.
It can also be `useExisting` , `useValue` , or `useFactory` .
2019-01-22 14:11:35 -05:00
Each of these keys provides a different type of dependency, as discussed below.
2018-05-31 15:02:50 -04:00
{@a class-provider}
2020-10-13 08:57:54 -04:00
## Specifying an alternative class provider
2018-05-31 15:02:50 -04:00
2020-10-13 08:57:54 -04:00
Different classes can provide the same service.
For example, the following code tells the injector to return a `BetterLogger` instance when the component asks for a logger using the `Logger` token.
2018-05-31 15:02:50 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-4" >
< / code-example >
{@a class-provider-dependencies}
2020-10-22 14:16:51 -04:00
### Configuring class providers with dependencies
If the alternative class providers have their own dependencies, specify both providers in the `providers` metadata property of the parent module or component.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-5" > < / code-example >
In this example, `EvenBetterLogger` displays the user name in the log message.
2018-05-31 15:02:50 -04:00
This logger gets the user from an injected `UserService` instance.
2019-07-20 13:40:17 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "EvenBetterLogger" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
The injector needs providers for both this new logging service and its dependent `UserService` .
2018-05-31 15:02:50 -04:00
{@a aliased-class-providers}
2020-10-22 14:16:51 -04:00
### Aliasing class providers
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To alias a class provider, specify the alias and the class provider in the `providers` array with the `useExisting` property.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
In the following example, the injector injects the singleton instance of `NewLogger` when the component asks for either the new or the old logger.
In this way, `OldLogger` is an alias for `NewLogger` .
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-6b" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Be sure you don't alias `OldLogger` to `NewLogger` with `useClass` , as this creates two different `NewLogger` instances.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
{@a provideparent}
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
## Aliasing a class interface
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Generally, writing variations of the same parent alias provider uses [forwardRef ](guide/dependency-injection-in-action#forwardref ) as follows.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection-in-action/src/app/parent-finder.component.ts" region = "alex-providers" header = "dependency-injection-in-action/src/app/parent-finder.component.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To streamline your code, you can extract that logic into a helper function using the `provideParent()` helper function.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection-in-action/src/app/parent-finder.component.ts" region = "provide-the-parent" header = "dependency-injection-in-action/src/app/parent-finder.component.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Now you can add a parent provider to your components that's easier to read and understand.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection-in-action/src/app/parent-finder.component.ts" region = "alice-providers" header = "dependency-injection-in-action/src/app/parent-finder.component.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
### Aliasing multiple class interfaces
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To alias multiple parent types, each with its own class interface token, configure `provideParent()` to accept more arguments.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection-in-action/src/app/parent-finder.component.ts" region = "provide-parent" header = "dependency-injection-in-action/src/app/parent-finder.component.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Next, to use `provideParent()` with a different parent type, provide a second argument, here `DifferentParent` .
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection-in-action/src/app/parent-finder.component.ts" region = "beth-providers" header = "dependency-injection-in-action/src/app/parent-finder.component.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
{@a value-provider}
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
## Injecting an object
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To inject an object, configure the injector with the `useValue` option.
The following provider object uses the `useValue` key to associate the variable with the `Logger` token.
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-7" > < / code-example >
In this example, `SilentLogger` is an object that fulfills the logger role.
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "silent-logger" > < / code-example >
{@a non-class-dependencies}
### Injecting a configuration object
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
A common use case for object literals is a configuration object.
The following configuration object includes the title of the application and the address of a web API endpoint.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection/src/app/app.config.ts" region = "config" header = "src/app/app.config.ts (excerpt)" > < / code-example >
To provide and inject the configuration object, specify the object in the `@NgModule()` `providers` array.
2018-05-31 15:02:50 -04:00
2018-10-11 07:29:59 -04:00
< code-example path = "dependency-injection/src/app/app.module.ts" region = "providers" header = "src/app/app.module.ts (providers)" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
{@a injectiontoken}
### Using an `InjectionToken` object
You can define and use an `InjectionToken` object for choosing a provider token for non-class dependencies.
The following example defines a token, `APP_CONFIG` of the type `InjectionToken` .
2018-05-31 15:02:50 -04:00
2019-07-20 13:40:17 -04:00
< code-example path = "dependency-injection/src/app/app.config.ts" region = "token" header = "src/app/app.config.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2021-01-04 12:21:28 -05:00
The optional type parameter, `<AppConfig>` , and the token description, `app.config` , specify the token's purpose.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Next, register the dependency provider in the component using the `InjectionToken` object of `APP_CONFIG` .
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" header = "src/app/providers.component.ts" region = "providers-9" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Now you can inject the configuration object into the constructor with `@Inject()` parameter decorator.
2018-05-31 15:02:50 -04:00
2019-07-20 13:40:17 -04:00
< code-example path = "dependency-injection/src/app/app.component.2.ts" region = "ctor" header = "src/app/app.component.ts" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
{@a di-and-interfaces}
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
#### Interfaces and dependency injection
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Though the TypeScript `AppConfig` interface supports typing within the class, the `AppConfig` interface plays no role in dependency injection.
In TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation, or token, that the DI framework can use.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
When the transpiler changes TypeScript to JavaScript, the interface disappears because JavaScript doesn't have interfaces.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Since there is no interface for Angular to find at runtime, the interface cannot be a token, nor can you inject it.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "providers-9-interface" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
< code-example path = "dependency-injection/src/app/providers.component.ts" region = "provider-9-ctor-interface" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
{@a factory-provider}
{@a factory-providers}
## Using factory providers
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To create a changeable, dependent value based on information unavailable before run time, you can use a factory provider.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
In the following example, only authorized users should see secret heroes in the `HeroService` .
Authorization can change during the course of a single application session, as when a different user logs in .
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To keep security-sensitive information in `UserService` and out of `HeroService` , give the `HeroService` constructor a boolean flag to control display of secret heroes.
2018-05-31 15:02:50 -04:00
2019-07-20 13:40:17 -04:00
< code-example path = "dependency-injection/src/app/heroes/hero.service.ts" region = "internals" header = "src/app/heroes/hero.service.ts (excerpt)" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
To implement the `isAuthorized` flag, use a factory provider to create a new logger instance for `HeroService` .
2018-05-31 15:02:50 -04:00
2019-07-20 13:40:17 -04:00
< code-example path = "dependency-injection/src/app/heroes/hero.service.provider.ts" region = "factory" header = "src/app/heroes/hero.service.provider.ts (excerpt)" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
The factory function has access to `UserService` .
You inject both `Logger` and `UserService` into the factory provider so the injector can pass them along to the factory function.
2018-05-31 15:02:50 -04:00
2019-07-20 13:40:17 -04:00
< code-example path = "dependency-injection/src/app/heroes/hero.service.provider.ts" region = "provider" header = "src/app/heroes/hero.service.provider.ts (excerpt)" > < / code-example >
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
* The `useFactory` field specifies that the provider is a factory function whose implementation is `heroServiceFactory` .
2018-05-31 15:02:50 -04:00
2020-10-13 08:57:54 -04:00
* The `deps` property is an array of [provider tokens ](#token ).
2018-05-31 15:02:50 -04:00
The `Logger` and `UserService` classes serve as tokens for their own class providers.
2020-10-22 14:16:51 -04:00
The injector resolves these tokens and injects the corresponding services into the matching `heroServiceFactory` factory function parameters.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
Capturing the factory provider in the exported variable, `heroServiceProvider` , makes the factory provider reusable.
2018-05-31 15:02:50 -04:00
2020-10-22 14:16:51 -04:00
The following side-by-side example shows how `heroServiceProvider` replaces `HeroService` in the `providers` array.
2018-05-31 15:02:50 -04:00
< code-tabs >
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/heroes/heroes.component (v3)" path = "dependency-injection/src/app/heroes/heroes.component.ts" >
2018-05-31 15:02:50 -04:00
< / code-pane >
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/heroes/heroes.component (v2)" path = "dependency-injection/src/app/heroes/heroes.component.1.ts" >
2018-05-31 15:02:50 -04:00
< / code-pane >
< / code-tabs >