2019-02-13 12:50:30 -05:00
# Hierarchical injectors
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
Injectors in Angular have rules that you can leverage to
2019-08-23 09:02:26 -04:00
achieve the desired visibility of injectables in your apps.
2019-02-13 12:50:30 -05:00
By understanding these rules, you can determine in which
2019-09-07 11:48:40 -04:00
NgModule, Component or Directive you should declare a provider.
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
## Two injector hierarchies
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
There are two injector hierarchies in Angular:
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
1. `ModuleInjector` hierarchy— configure a `ModuleInjector`
in this hierarchy using an `@NgModule()` or `@Injectable()` annotation.
1. `ElementInjector` hierarchy— created implicitly at each
DOM element. An `ElementInjector` is empty by default
unless you configure it in the `providers` property on
`@Directive()` or `@Component()` .
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
{@a register-providers-injectable}
### `ModuleInjector`
The `ModuleInjector` can be configured in one of two ways:
* Using the `@Injectable()` `providedIn` property to
refer to `@NgModule()` , or `root` .
* Using the `@NgModule()` `providers` array.
< div class = "is-helpful alert" >
< h4 > Tree-shaking and < code > @Injectable()< / code > < / h4 >
Using the `@Injectable()` `providedIn` property is preferable
to the `@NgModule()` `providers`
array because with `@Injectable()` `providedIn` , optimization
tools can perform
tree-shaking, which removes services that your app isn't
using and results in smaller bundle sizes.
Tree-shaking is especially useful for a library
because the application which uses the library may not have
a need to inject it. Read more
about [tree-shakable providers ](guide/dependency-injection-providers#tree-shakable-providers )
in [DI Providers ](guide/dependency-injection-providers ).
< / div >
`ModuleInjector` is configured by the `@NgModule.providers` and
`NgModule.imports` property. `ModuleInjector` is a flattening of
all of the providers arrays which can be reached by following the
`NgModule.imports` recursively.
Child `ModuleInjector` s are created when lazy loading other `@NgModules` .
Provide services with the `providedIn` property of `@Injectable()` as follows:
```ts
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
import { Injectable } from '@angular/core';
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
@Injectable ({
providedIn: 'root' // < --provides this service in the root ModuleInjector
})
export class ItemService {
name = 'telephone';
}
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
```
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
The `@Injectable()` decorator identifies a service class.
The `providedIn` property configures a specific `ModuleInjector` ,
here `root` , which makes the service available in the `root` `ModuleInjector` .
#### Platform injector
There are two more injectors above `root` , an
additional `ModuleInjector` and `NullInjector()` .
Consider how Angular bootstraps the app with the
following in `main.ts` :
```javascript
platformBrowserDynamic().bootstrapModule(AppModule).then(ref => {...})
```
The `bootstrapModule()` method creates a child injector of
the platform injector which is configured by the `AppModule` .
This is the `root` `ModuleInjector` .
The `platformBrowserDynamic()` method creates an injector
configured by a `PlatformModule` , which contains platform-specific
dependencies. This allows multiple apps to share a platform
configuration.
For example, a browser has only one URL bar, no matter how
many apps you have running.
You can configure additional platform-specific providers at the
platform level by supplying `extraProviders` using the `platformBrowser()` function.
The next parent injector in the hierarchy is the `NullInjector()` ,
which is the top of the tree. If you've gone so far up the tree
that you are looking for a service in the `NullInjector()` , you'll
get an error unless you've used `@Optional()` because ultimately,
everything ends at the `NullInjector()` and it returns an error or,
in the case of `@Optional()` , `null` . For more information on
`@Optional()` , see the [`@Optional()` section ](guide/hierarchical-dependency-injection#optional ) of this guide.
The following diagram represents the relationship between the
`root` `ModuleInjector` and its parent injectors as the
previous paragraphs describe.
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = "generated/images/guide/dependency-injection/injectors.svg" alt = "NullInjector, ModuleInjector, root injector" >
< / div >
2019-02-13 12:50:30 -05:00
While the name `root` is a special alias, other `ModuleInjector` s
don't have aliases. You have the option to create `ModuleInjector` s
whenever a dynamically loaded component is created, such as with
the Router, which will create child `ModuleInjector` s.
All requests forward up to the root injector, whether you configured it
with the `bootstrapModule()` method, or registered all providers
with `root` in their own services.
2017-03-27 11:08:53 -04:00
2018-10-17 08:58:11 -04:00
< div class = "alert is-helpful" >
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
< h4 > < code > @Injectable()< / code > vs. < code > @NgModule()< / code > < / h4 >
If you configure an app-wide provider in the `@NgModule()` of
`AppModule` , it overrides one configured for `root` in the
`@Injectable()` metadata. You can do this to configure a
non-default provider of a service that is shared with multiple apps.
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
Here is an example of the case where the component router
configuration includes
a non-default [location strategy ](guide/router#location-strategy )
by listing its provider
in the `providers` list of the `AppModule` .
< code-example path = "dependency-injection-in-action/src/app/app.module.ts" region = "providers" header = "src/app/app.module.ts (providers)" >
< / code-example >
< / div >
### `ElementInjector`
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
Angular creates `ElementInjector` s implicitly for each DOM element.
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
Providing a service in the `@Component()` decorator using
its `providers` or `viewProviders`
property configures an `ElementInjector` .
For example, the following `TestComponent` configures the `ElementInjector`
by providing the service as follows:
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
```ts
@Component ({
...
providers: [{ provide: ItemService, useValue: { name: 'lamp' } }]
})
export class TestComponent
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
```
< div class = "alert is-helpful" >
2019-08-23 09:02:26 -04:00
**Note:** Please see the
[resolution rules ](guide/hierarchical-dependency-injection#resolution-rules )
section to understand the relationship between the `ModuleInjector` tree and
the `ElementInjector` tree.
2019-02-13 12:50:30 -05:00
< / div >
2017-02-22 13:09:39 -05:00
2017-03-30 15:04:18 -04:00
2019-02-13 12:50:30 -05:00
When you provide services in a component, that service is available via
the `ElementInjector` at that component instance.
It may also be visible at
child component/directives based on visibility rules described in the [resolution rules ](guide/hierarchical-dependency-injection#resolution-rules ) section.
2017-02-22 13:09:39 -05:00
2018-05-31 15:02:50 -04:00
When the component instance is destroyed, so is that service instance.
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
#### `@Directive()` and `@Component()`
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
A component is a special type of directive, which means that
just as `@Directive()` has a `providers` property, `@Component()` does too.
This means that directives as well as components can configure
providers, using the `providers` property.
When you configure a provider for a component or directive
using the `providers` property,
that provider belongs to the `ElementInjector` of that component or
directive.
Components and directives on the same element share an injector.
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
{@a resolution-rules}
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
## Resolution rules
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
When resolving a token for a component/directive, Angular
resolves it in two phases:
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
1. Against the `ElementInjector` hierarchy (its parents)
1. Against the `ModuleInjector` hierarchy (its parents)
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
When a component declares a dependency, Angular tries to satisfy that
dependency with its own `ElementInjector` .
If the component's injector lacks the provider, it passes the request
up to its parent component's `ElementInjector` .
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
The requests keep forwarding up until Angular finds an injector that can
handle the request or runs out of ancestor `ElementInjector` s.
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
If Angular doesn't find the provider in any `ElementInjector` s,
it goes back to the element where the request originated and looks
in the `ModuleInjector` hierarchy.
If Angular still doesn't find the provider, it throws an error.
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
If you have registered a provider for the same DI token at
different levels, the first one Angular encounters is the one
it uses to resolve the dependency. If, for example, a provider
is registered locally in the component that needs a service,
Angular doesn't look for another provider of the same service.
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
## Resolution modifiers
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
Angular's resolution behavior can be modified with `@Optional()` , `@Self()` ,
`@SkipSelf()` and `@Host()` . Import each of them from `@angular/core`
and use each in the component class constructor when you inject your service.
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
For a working app showcasing the resolution modifiers that
this section covers, see the < live-example name = "resolution-modifiers" > resolution modifiers example< / live-example > .
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
### Types of modifiers
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
Resolution modifiers fall into three categories:
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
1. What to do if Angular doesn't find what you're
looking for, that is `@Optional()`
2. Where to start looking, that is `@SkipSelf()`
3. Where to stop looking, `@Host()` and `@Self()`
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
By default, Angular always starts at the current `Injector` and keeps
searching all the way up. Modifiers allow you to change the starting
(self) or ending location.
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
Additionally, you can combine all of the modifiers except `@Host()` and `@Self()` and of course `@Skipself()` and `@Self()` .
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
{@a optional}
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
### `@Optional()`
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
`@Optional()` allows Angular to consider a service you inject to be optional.
This way, if it can't be resolved at runtime, Angular simply
resolves the service as `null` , rather than throwing an error. In
the following example, the service, `OptionalService` , isn't provided in
the service, `@NgModule()` , or component class, so it isn't available
anywhere in the app.
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
< code-example path = "resolution-modifiers/src/app/optional/optional.component.ts" header = "resolution-modifiers/src/app/optional/optional.component.ts" region = "optional-component" >
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
< / code-example >
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
### `@Self()`
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
Use `@Self()` so that Angular will only look at the `ElementInjector` for the current component or directive.
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
A good use case for `@Self()` is to inject a service but only if it is
available on the current host element. To avoid errors in this situation,
combine `@Self()` with `@Optional()` .
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
For example, in the following `SelfComponent` , notice
the injected `LeafService` in
the constructor.
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
< code-example path = "resolution-modifiers/src/app/self-no-data/self-no-data.component.ts" header = "resolution-modifiers/src/app/self-no-data/self-no-data.component.ts" region = "self-no-data-component" >
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
< / code-example >
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
In this example, there is a parent provider and injecting the
service will return the value, however, injecting the service
with `@Self()` and `@Optional()` will return `null` because
`@Self()` tells the injector to stop searching in the current
host element.
2017-03-11 08:44:25 -05:00
2019-02-13 12:50:30 -05:00
Another example shows the component class with a provider
for `FlowerService` . In this case, the injector looks no further
than the current `ElementInjector` because it finds the `FlowerService` and returns the yellow flower 🌼.
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
< code-example path = "resolution-modifiers/src/app/self/self.component.ts" header = "resolution-modifiers/src/app/self/self.component.ts" region = "self-component" >
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
< / code-example >
### `@SkipSelf()`
`@SkipSelf()` is the opposite of `@Self()` . With `@SkipSelf()` , Angular
starts its search for a service in the parent `ElementInjector` , rather than
in the current one. So if the parent `ElementInjector` were using the value `🌿` (fern)
for `emoji` , but you had `🍁` (maple leaf) in the component's `providers` array,
Angular would ignore `🍁` (maple leaf) and use `🌿` (fern).
To see this in code, assume that the following value for `emoji` is what the parent component were using, as in this service:
< code-example path = "resolution-modifiers/src/app/leaf.service.ts" header = "resolution-modifiers/src/app/leaf.service.ts" region = "leafservice" >
< / code-example >
Imagine that in the child component, you had a different value, `🍁` (maple leaf) but you wanted to use the parent's value instead. This is when you'd use `@SkipSelf()` :
< code-example path = "resolution-modifiers/src/app/skipself/skipself.component.ts" header = "resolution-modifiers/src/app/skipself/skipself.component.ts" region = "skipself-component" >
< / code-example >
In this case, the value you'd get for `emoji` would be `🌿` (fern), not `🍁` (maple leaf).
#### `@SkipSelf()` with `@Optional()`
Use `@SkipSelf()` with `@Optional()` to prevent an error if the value is `null` . In the following example, the `Person` service is injected in the constructor. `@SkipSelf()` tells Angular to skip the current injector and `@Optional()` will prevent an error should the `Person` service be `null` .
``` ts
class Person {
constructor(@Optional() @SkipSelf () parent: Person) {}
}
```
### `@Host()`
`@Host()` lets you designate a component as the last stop in the injector tree when searching for providers. Even if there is a service instance further up the tree, Angular won't continue looking. Use `@Host()` as follows:
< code-example path = "resolution-modifiers/src/app/host/host.component.ts" header = "resolution-modifiers/src/app/host/host.component.ts" region = "host-component" >
< / code-example >
Since `HostComponent` has `@Host()` in its constructor, no
matter what the parent of `HostComponent` might have as a
`flower.emoji` value,
the `HostComponent` will use `🌼` (yellow flower).
## Logical structure of the template
When you provide services in the component class, services are
visible within the `ElementInjector` tree relative to where
and how you provide those services.
Understanding the underlying logical structure of the Angular
template will give you a foundation for configuring services
and in turn control their visibility.
Components are used in your templates, as in the following example:
```
< app-root >
< app-child > < / app-child >
< / app-root >
```
< div class = "alert is-helpful" >
**Note:** Usually, you declare the components and their
templates in separate files. For the purposes of understanding
how the injection system works, it is useful to look at them
from the point of view of a combined logical tree. The term
logical distinguishes it from the render tree (your application
2019-10-26 10:35:03 -04:00
DOM tree). To mark the locations of where the component
2019-02-13 12:50:30 -05:00
templates are located, this guide uses the `<#VIEW>`
pseudo element, which doesn't actually exist in the render tree
and is present for mental model purposes only.
< / div >
The following is an example of how the `<app-root>` and `<app-child>` view trees are combined into a single logical tree:
```
< app-root >
< #VIEW>
< app-child >
< #VIEW>
...content goes here...
< /#VIEW>
< / app-child >
< #VIEW>
< / app-root >
```
Understanding the idea of the `<#VIEW>` demarcation is especially significant when you configure services in the component class.
## Providing services in `@Component()`
How you provide services via an `@Component()` (or `@Directive()` )
decorator determines their visibility. The following sections
demonstrate `providers` and `viewProviders` along with ways to
modify service visibility with `@SkipSelf()` and `@Host()` .
A component class can provide services in two ways:
1. with a `providers` array
```typescript=
@Component ({
...
providers: [
{provide: FlowerService, useValue: {emoji: '🌺'}}
]
})
```
2. with a `viewProviders` array
```typescript=
@Component ({
...
viewProviders: [
{provide: AnimalService, useValue: {emoji: '🐶'}}
]
})
```
To understand how the `providers` and `viewProviders` influence service
visibility differently, the following sections build
a < live-example name = "providers-viewproviders" > < / live-example >
step-by-step and compare the use of `providers` and `viewProviders`
in code and a logical tree.
< div class = "alert is-helpful" >
**NOTE:** In the logical tree, you'll see `@Provide` , `@Inject` , and
`@NgModule` , which are not real HTML attributes but are here to demonstrate
what is going on under the hood.
- `@Inject(Token)=>Value` demonstrates that if `Token` is injected at
this location in the logical tree its value would be `Value` .
- `@Provide(Token=Value)` demonstrates that there is a declaration of
`Token` provider with value `Value` at this location in the logical tree.
- `@NgModule(Token)` demonstrates that a fallback `NgModule` injector
should be used at this location.
< / div >
### Example app structure
The example app has a `FlowerService` provided in `root` with an `emoji`
value of `🌺` (red hibiscus).
< code-example path = "providers-viewproviders/src/app/flower.service.ts" header = "providers-viewproviders/src/app/flower.service.ts" region = "flowerservice" >
< / code-example >
Consider a simple app with only an `AppComponent` and a `ChildComponent` .
The most basic rendered view would look like nested HTML elements such as
the following:
```
< app-root > <!-- AppComponent selector -->
< app-child > <!-- ChildComponent selector -->
< / app-child >
< / app-root >
```
However, behind the scenes, Angular uses a logical view
representation as follows when resolving injection requests:
```
< app-root > <!-- AppComponent selector -->
< #VIEW>
< app-child > <!-- ChildComponent selector -->
< #VIEW>
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
The `<#VIEW>` here represents an instance of a template.
Notice that each component has its own `<#VIEW>` .
Knowledge of this structure can inform how you provide and
inject your services, and give you complete control of service visibility.
Now, consider that `<app-root>` simply injects the `FlowerService` :
< code-example path = "providers-viewproviders/src/app/app.component.1.ts" header = "providers-viewproviders/src/app/app.component.ts" region = "injection" >
< / code-example >
Add a binding to the `<app-root>` template to visualize the result:
< code-example path = "providers-viewproviders/src/app/app.component.html" header = "providers-viewproviders/src/app/app.component.html" region = "binding-flower" >
< / code-example >
The output in the view would be:
```
Emoji from FlowerService: 🌺
```
In the logical tree, this would be represented as follows:
```
< app-root @NgModule ( AppModule )
@Inject (FlowerService) flower=>"🌺">
< #VIEW>
< p > Emoji from FlowerService: {{flower.emoji}} (🌺)< / p >
< app-child >
< #VIEW>
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
2019-10-26 10:35:03 -04:00
When `<app-root>` requests the `FlowerService` , it is the injector's job
2019-02-13 12:50:30 -05:00
to resolve the `FlowerService` token. The resolution of the token happens
in two phases:
1. The injector determines the starting location in the logical tree and
an ending location of the search. The injector begins with the starting
location and looks for the token at each level in the logical tree. If
the token is found it is returned.
2. If the token is not found, the injector looks for the closest
parent `@NgModule()` to delegate the request to.
In the example case, the constraints are:
1. Start with `<#VIEW>` belonging to `<app-root>` and end with `<app-root>` .
- Normally the starting point for search is at the point
of injection. However, in this case `<app-root>` `@Component` s
are special in that they also include their own `viewProviders` ,
which is why the search starts at `<#VIEW>` belonging to `<app-root>` .
(This would not be the case for a directive matched at the same location).
- The ending location just happens to be the same as the component
itself, because it is the topmost component in this application.
2019-08-23 09:02:26 -04:00
2. The `AppModule` acts as the fallback injector when the
2019-02-13 12:50:30 -05:00
injection token can't be found in the `ElementInjector` s.
### Using the `providers` array
Now, in the `ChildComponent` class, add a provider for `FlowerService`
to demonstrate more complex resolution rules in the upcoming sections:
< code-example path = "providers-viewproviders/src/app/child/child.component.1.ts" header = "providers-viewproviders/src/app/child.component.ts" region = "flowerservice" >
< / code-example >
Now that the `FlowerService` is provided in the `@Component()` decorator,
when the `<app-child>` requests the service, the injector has only to look
as far as the `<app-child>` 's own `ElementInjector` . It won't have to
continue the search any further through the injector tree.
The next step is to add a binding to the `ChildComponent` template.
< code-example path = "providers-viewproviders/src/app/child/child.component.html" header = "providers-viewproviders/src/app/child.component.html" region = "flower-binding" >
< / code-example >
To render the new values, add `<app-child>` to the bottom of
2019-10-26 13:00:38 -04:00
the `AppComponent` template so the view also displays the sunflower:
2019-02-13 12:50:30 -05:00
```
Child Component
Emoji from FlowerService: 🌻
```
In the logical tree, this would be represented as follows:
```
2019-08-23 09:02:26 -04:00
< app-root @NgModule ( AppModule )
2019-02-13 12:50:30 -05:00
@Inject (FlowerService) flower=>"🌺">
< #VIEW>
< p > Emoji from FlowerService: {{flower.emoji}} (🌺)< / p >
< app-child @Provide ( FlowerService = "🌻" )
@Inject (FlowerService)=>"🌻"> <!-- search ends here -->
< #VIEW> <!-- search starts here -->
< h2 > Parent Component< / h2 >
< p > Emoji from FlowerService: {{flower.emoji}} (🌻)< / p >
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
When `<app-child>` requests the `FlowerService` , the injector begins
its search at the `<#VIEW>` belonging to `<app-child>` (`< #VIEW>` is
included because it is injected from `@Component()` ) and ends with
`<app-child>` . In this case, the `FlowerService` is resolved in the
`<app-child>` 's `providers` array with sunflower 🌻. The injector doesn't
2019-09-07 11:48:40 -04:00
have to look any further in the injector tree. It stops as soon as it
2019-02-13 12:50:30 -05:00
finds the `FlowerService` and never sees the 🌺 (red hibiscus).
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
{@a use-view-providers}
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
### Using the `viewProviders` array
Use the `viewProviders` array as another way to provide services in the
`@Component()` decorator. Using `viewProviders` makes services
visibile in the `<#VIEW>` .
< div class = "is-helpful alert" >
The steps are the same as using the `providers` array,
with the exception of using the `viewProviders` array instead.
For step-by-step instructions, continue with this section. If you can
set it up on your own, skip ahead to [Modifying service availability ](guide/hierarchical-dependency-injection#modify-visibility ).
< / div >
The example app features a second service, the `AnimalService` to
demonstrate `viewProviders` .
2019-09-07 11:48:40 -04:00
First, create an `AnimalService` with an `emoji` property of 🐳 (whale):
2019-02-13 12:50:30 -05:00
< code-example path = "providers-viewproviders/src/app/animal.service.ts" header = "providers-viewproviders/src/app/animal.service.ts" region = "animal-service" >
< / code-example >
Following the same pattern as with the `FlowerService` , inject the
`AnimalService` in the `AppComponent` class:
< code-example path = "providers-viewproviders/src/app/app.component.ts" header = "providers-viewproviders/src/app/app.component.ts" region = "inject-animal-service" >
< / code-example >
2018-05-31 15:02:50 -04:00
< div class = "alert is-helpful" >
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
**Note:** You can leave all the `FlowerService` related code in place
as it will allow a comparison with the `AnimalService` .
< / div >
Add a `viewProviders` array and inject the `AnimalService` in the
`<app-child>` class, too, but give `emoji` a different value. Here,
it has a value of 🐶 (puppy).
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
< code-example path = "providers-viewproviders/src/app/child/child.component.ts" header = "providers-viewproviders/src/app/child.component.ts" region = "provide-animal-service" >
< / code-example >
2019-08-23 09:02:26 -04:00
Add bindings to the `ChildComponent` and the `AppComponent` templates.
2019-02-13 12:50:30 -05:00
In the `ChildComponent` template, add the following binding:
< code-example path = "providers-viewproviders/src/app/child/child.component.html" header = "providers-viewproviders/src/app/child.component.html" region = "animal-binding" >
< / code-example >
2018-05-31 15:02:50 -04:00
2019-02-13 12:50:30 -05:00
Additionally, add the same to the `AppComponent` template:
< code-example path = "providers-viewproviders/src/app/app.component.html" header = "providers-viewproviders/src/app/app.component.html" region = "binding-animal" >
< / code-example >
Now you should see both values in the browser:
```
AppComponent
Emoji from AnimalService: 🐳
Child Component
Emoji from AnimalService: 🐶
```
The logic tree for this example of `viewProviders` is as follows:
```
< app-root @NgModule ( AppModule )
@Inject (AnimalService) animal=>"🐳">
< #VIEW>
< app-child >
< #VIEW
@Provide (AnimalService="🐶")
@Inject (AnimalService=>"🐶")>
<!-- ^^using viewProviders means AnimalService is available in <#VIEW> -->
< p > Emoji from AnimalService: {{animal.emoji}} (🐶)< / p >
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
Just as with the `FlowerService` example, the `AnimalService` is provided
in the `<app-child>` `@Component()` decorator. This means that since the
injector first looks in the `ElementInjector` of the component, it finds the
`AnimalService` value of 🐶 (puppy). It doesn't need to continue searching the
`ElementInjector` tree, nor does it need to search the `ModuleInjector` .
### `providers` vs. `viewProviders`
To see the difference between using `providers` and `viewProviders` , add
another component to the example and call it `InspectorComponent` .
`InspectorComponent` will be a child of the `ChildComponent` . In
`inspector.component.ts` , inject the `FlowerService` and `AnimalService` in
the constructor:
< code-example path = "providers-viewproviders/src/app/inspector/inspector.component.ts" header = "providers-viewproviders/src/app/inspector/inspector.component.ts" region = "injection" >
< / code-example >
You do not need a `providers` or `viewProviders` array. Next, in
`inspector.component.html` , add the same markup from previous components:
< code-example path = "providers-viewproviders/src/app/inspector/inspector.component.html" header = "providers-viewproviders/src/app/inspector/inspector.component.html" region = "binding" >
< / code-example >
Remember to add the `InspectorComponent` to the `AppModule` `declarations` array.
< code-example path = "providers-viewproviders/src/app/app.module.ts" header = "providers-viewproviders/src/app/app.module.ts" region = "appmodule" >
< / code-example >
Next, make sure your `child.component.html` contains the following:
< code-example path = "providers-viewproviders/src/app/child/child.component.html" header = "providers-viewproviders/src/app/child/child.component.html" region = "child-component" >
< / code-example >
The first two lines, with the bindings, are there from previous steps. The
new parts are `<ng-content>` and `<app-inspector>` . `<ng-content>` allows
you to project content, and `<app-inspector>` inside the `ChildComponent`
template makes the `InspectorComponent` a child component of
`ChildComponent` .
Next, add the following to `app.component.html` to take advantage of content projection.
< code-example path = "providers-viewproviders/src/app/app.component.html" header = "providers-viewproviders/src/app/app.component.html" region = "content-projection" >
< / code-example >
The browser now renders the following, omitting the previous examples
for brevity:
```
//...Omitting previous examples. The following applies to this section.
Content projection: This is coming from content. Doesn't get to see
puppy because the puppy is declared inside the view only.
Emoji from FlowerService: 🌻
Emoji from AnimalService: 🐳
Emoji from FlowerService: 🌻
Emoji from AnimalService: 🐶
```
These four bindings demonstrate the difference between `providers`
and `viewProviders` . Since the 🐶 (puppy) is declared inside the < #VIEW>,
it isn't visible to the projected content. Instead, the projected
content sees the 🐳 (whale).
The next section though, where `InspectorComponent` is a child component
of `ChildComponent` , `InspectorComponent` is inside the `<#VIEW>` , so
when it asks for the `AnimalService` , it sees the 🐶 (puppy).
The `AnimalService` in the logical tree would look like this:
```
< app-root @NgModule ( AppModule )
@Inject (AnimalService) animal=>"🐳">
< #VIEW>
< app-child >
< #VIEW
@Provide (AnimalService="🐶")
@Inject (AnimalService=>"🐶")>
<!-- ^^using viewProviders means AnimalService is available in <#VIEW> -->
< p > Emoji from AnimalService: {{animal.emoji}} (🐶)< / p >
< app-inspector >
< p > Emoji from AnimalService: {{animal.emoji}} (🐶)< / p >
< / app-inspector >
< /#VIEW>
< app-inspector >
< #VIEW>
< p > Emoji from AnimalService: {{animal.emoji}} (🐳)< / p >
< /#VIEW>
< / app-inspector >
< / app-child >
< /#VIEW>
< / app-root >
```
2019-09-07 11:48:40 -04:00
The projected content of `<app-inspector>` sees the 🐳 (whale), not
2019-02-13 12:50:30 -05:00
the 🐶 (puppy), because the
🐶 (puppy) is inside the `<app-child>` `<#VIEW>` . The `<app-inspector>` can
only see the 🐶 (puppy)
if it is also within the `<#VIEW>` .
{@a modify-visibility}
## Modifying service visibility
This section describes how to limit the scope of the beginning and
ending `ElementInjector` using the visibility decorators `@Host()` ,
`@Self()` , and `@SkipSelf()` .
### Visibility of provided tokens
Visibility decorators influence where the search for the injection
token begins and ends in the logic tree. To do this, place
visibility decorators at the point of injection, that is, the
`constructor()` , rather than at a point of declaration.
To alter where the injector starts looking for `FlowerService` , add
`@SkipSelf()` to the `<app-child>` `@Inject` declaration for the
`FlowerService` . This declaration is in the `<app-child>` constructor
as shown in `child.component.ts` :
```typescript=
constructor(@SkipSelf() public flower : FlowerService) { }
```
With `@SkipSelf()` , the `<app-child>` injector doesn't look to itself for
the `FlowerService` . Instead, the injector starts looking for the
`FlowerService` at the `<app-root>` 's `ElementInjector` , where it finds
nothing. Then, it goes back to the `<app-child>` `ModuleInjector` and finds
the 🌺 (red hibiscus) value, which is available because the `<app-child>`
`ModuleInjector` and the `<app-root>` `ModuleInjector` are flattened into one
`ModuleInjector` . Thus, the UI renders the following:
```
Emoji from FlowerService: 🌺
```
In a logical tree, this same idea might look like this:
```
2019-08-23 09:02:26 -04:00
< app-root @NgModule ( AppModule )
2019-02-13 12:50:30 -05:00
@Inject (FlowerService) flower=>"🌺">
< #VIEW>
< app-child @Provide ( FlowerService = "🌻" ) >
< #VIEW @Inject (FlowerService, SkipSelf)=>"🌺">
<!-- With SkipSelf, the injector looks to the next injector up the tree -->
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
Though `<app-child>` provides the 🌻 (sunflower), the app renders
the 🌺 (red hibiscus) because `@SkipSelf()` causes the current
injector to skip
itself and look to its parent.
If you now add `@Host()` (in addition to the `@SkipSelf()` ) to the
`@Inject` of the `FlowerService` , the result will be `null` . This is
because `@Host()` limits the upper bound of the search to the
`<#VIEW>` . Here's the idea in the logical tree:
```
2019-08-23 09:02:26 -04:00
< app-root @NgModule ( AppModule )
2019-02-13 12:50:30 -05:00
@Inject (FlowerService) flower=>"🌺">
< #VIEW> <!-- end search here with null -->
< app-child @Provide ( FlowerService = "🌻" ) > <!-- start search here -->
< #VIEW @Inject (FlowerService, @SkipSelf , @Host , @Optional )=>null>
< /#VIEW>
< / app-parent >
< /#VIEW>
< / app-root >
```
Here, the services and their values are the same, but `@Host()`
stops the injector from looking any further than the `<#VIEW>`
for `FlowerService` , so it doesn't find it and returns `null` .
< div class = "alert is-helpful" >
**Note:** The example app uses `@Optional()` so the app does
not throw an error, but the principles are the same.
2018-05-31 15:02:50 -04:00
< / div >
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
### `@SkipSelf()` and `viewProviders`
The `<app-child>` currently provides the `AnimalService` in
the `viewProviders` array with the value of 🐶 (puppy). Because
the injector has only to look at the `<app-child>` 's `ElementInjector`
for the `AnimalService` , it never sees the 🐳 (whale).
Just as in the `FlowerService` example, if you add `@SkipSelf()`
to the constructor for the `AnimalService` , the injector won't
2019-08-23 09:02:26 -04:00
look in the current `<app-child>` 's `ElementInjector` for the
2019-02-13 12:50:30 -05:00
`AnimalService` .
```typescript=
export class ChildComponent {
// add @SkipSelf ()
constructor(@SkipSelf() public animal : AnimalService) { }
}
```
2019-08-23 09:02:26 -04:00
Instead, the injector will begin at the `<app-root>`
2019-02-13 12:50:30 -05:00
`ElementInjector` . Remember that the `<app-child>` class
provides the `AnimalService` in the `viewProviders` array
with a value of 🐶 (puppy):
```ts
@Component ({
selector: 'app-child',
...
viewProviders:
[{ provide: AnimalService, useValue: { emoji: '🐶' } }]
})
```
The logical tree looks like this with `@SkipSelf()` in `<app-child>` :
```
2019-08-23 09:02:26 -04:00
< app-root @NgModule ( AppModule )
2019-02-13 12:50:30 -05:00
@Inject (AnimalService=>"🐳")>
< #VIEW><!-- search begins here -->
< app-child >
< #VIEW
@Provide (AnimalService="🐶")
@Inject (AnimalService, SkipSelf=>"🐳")>
<!--Add @SkipSelf -->
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
With `@SkipSelf()` in the `<app-child>` , the injector begins its
search for the `AnimalService` in the `<app-root>` `ElementInjector`
and finds 🐳 (whale).
### `@Host()` and `viewProviders`
If you add `@Host()` to the constructor for `AnimalService` , the
result is 🐶 (puppy) because the injector finds the `AnimalService`
in the `<app-child>` `<#VIEW>` . Here is the `viewProviders` array
in the `<app-child>` class and `@Host()` in the constructor:
```typescript=
@Component ({
selector: 'app-child',
...
viewProviders:
[{ provide: AnimalService, useValue: { emoji: '🐶' } }]
})
export class ChildComponent {
constructor(@Host() public animal : AnimalService) { }
}
```
`@Host()` causes the injector to look until it encounters the edge of the `<#VIEW>` .
```
< app-root @NgModule ( AppModule )
@Inject (AnimalService=>"🐳")>
< #VIEW>
< app-child >
< #VIEW
@Provide (AnimalService="🐶")
@Inject (AnimalService, @Host =>"🐶")> <!-- @Host stops search here -->
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
2019-08-23 09:02:26 -04:00
Add a `viewProviders` array with a third animal, 🦔 (hedgehog), to the
`app.component.ts` `@Component()` metadata:
```typescript
@Component ({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
viewProviders: [{ provide: AnimalService, useValue: { emoji: '🦔' } }]
})
```
Next, add `@SkipSelf()` along with `@Host()` to the constructor for the
`Animal Service` in `child.component.ts` . Here are `@Host()`
and `@SkipSelf()` in the `<app-child>`
2019-02-13 12:50:30 -05:00
constructor :
```ts
export class ChildComponent {
constructor(
@Host () @SkipSelf () public animal : AnimalService) { }
}
```
When `@Host()` and `SkipSelf()` were applied to the `FlowerService` ,
which is in the `providers` array, the result was `null` because
`@SkipSelf()` starts its search in the `<app-child>` injector, but
`@Host()` stops searching at `<#VIEW>` — where there is no
`FlowerService` . In the logical tree, you can see that the
`FlowerService` is visible in `<app-child>` , not its `<#VIEW>` .
However, the `AnimalService` , which is provided in the
2019-08-23 09:02:26 -04:00
`AppComponent` `viewProviders` array, is visible.
2019-02-13 12:50:30 -05:00
The logical tree representation shows why this is:
```html
2019-08-23 09:02:26 -04:00
< app-root @NgModule ( AppModule )
2019-02-13 12:50:30 -05:00
@Inject (AnimalService=>"🐳")>
2019-08-23 09:02:26 -04:00
< #VIEW @Provide (AnimalService="🦔")
@Inject (AnimalService, @SkipSelf , @Host , @Optional )=>"🦔">
<!-- ^^@SkipSelf() starts here, @Host () stops here^^ -->
2019-02-13 12:50:30 -05:00
< app-child >
< #VIEW @Provide (AnimalService="🐶")
@Inject (AnimalService, @SkipSelf , @Host , @Optional )=>"🐶">
<!-- Add @SkipSelf ^^-->
< /#VIEW>
< / app-child >
< /#VIEW>
< / app-root >
```
`@SkipSelf()` , causes the injector to start its search for
the `AnimalService` at the `<app-root>` , not the `<app-child>` ,
where the request originates, and `@Host()` stops the search
at the `<app-root>` `<#VIEW>` . Since `AnimalService` is
2019-08-23 09:02:26 -04:00
provided via the `viewProviders` array, the injector finds 🦔
(hedgehog) in the `<#VIEW>` .
2019-02-13 12:50:30 -05:00
2018-05-31 15:02:50 -04:00
{@a component-injectors}
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
## `ElementInjector` use case examples
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
The ability to configure one or more providers at different levels
opens up useful possibilities.
For a look at the following scenarios in a working app, see the < live-example > heroes use case examples< / live-example > .
2017-03-11 08:44:25 -05:00
2017-02-22 13:09:39 -05:00
### Scenario: service isolation
2019-07-20 13:40:17 -04:00
Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.
2018-05-31 15:02:50 -04:00
For example, the guide sample includes a `VillainsListComponent` that displays a list of villains.
2017-02-22 13:09:39 -05:00
It gets those villains from a `VillainsService` .
2019-02-13 12:50:30 -05:00
If you provided `VillainsService` in the root `AppModule`
(where you registered the `HeroesService` ),
that would make the `VillainsService` visible everywhere in the
application, including the _Hero_ workflows. If you later
modified the `VillainsService` , you could break something in a
hero component somewhere.
2017-02-22 13:09:39 -05:00
2018-05-31 15:02:50 -04:00
Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
< code-example path = "hierarchical-dependency-injection/src/app/villains-list.component.ts" header = "src/app/villains-list.component.ts (metadata)" region = "metadata" >
< / code-example >
2017-03-27 11:08:53 -04:00
2017-03-11 08:44:25 -05:00
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
2017-02-22 13:09:39 -05:00
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
2019-02-13 12:50:30 -05:00
`VillainService` is a singleton with respect to `VillainsListComponent`
because that is where it is declared. As long as `VillainsListComponent`
does not get destroyed it will be the same instance of `VillainService`
but if there are multilple instances of `VillainsListComponent` , then each
instance of `VillainsListComponent` will have its own instance of `VillainService` .
2017-02-22 13:09:39 -05:00
### Scenario: multiple edit sessions
Many applications allow users to work on several open tasks at the same time.
2017-03-11 08:44:25 -05:00
For example, in a tax preparation application, the preparer could be working on several tax returns,
2017-02-22 13:09:39 -05:00
switching from one to the other throughout the day.
This guide demonstrates that scenario with an example in the Tour of Heroes theme.
Imagine an outer `HeroListComponent` that displays a list of super heroes.
2017-03-11 08:44:25 -05:00
To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return.
2017-02-22 13:09:39 -05:00
Each selected hero tax return opens in its own component and multiple returns can be open at the same time.
2017-03-11 08:44:25 -05:00
Each tax return component has the following characteristics:
2017-03-27 11:08:53 -04:00
2017-03-11 08:44:25 -05:00
* Is its own tax return editing session.
* Can change a tax return without affecting a return in another component.
* Has the ability to save the changes to its tax return or cancel them.
2017-02-22 13:09:39 -05:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = "generated/images/guide/dependency-injection/hid-heroes-anim.gif" alt = "Heroes in action" >
< / div >
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
Suppose that the `HeroTaxReturnComponent` had logic to manage and restore changes.
2017-03-11 08:44:25 -05:00
That would be a pretty easy task for a simple hero tax return.
2017-02-22 13:09:39 -05:00
In the real world, with a rich tax return data model, the change management would be tricky.
2018-05-31 15:02:50 -04:00
You could delegate that management to a helper service, as this example does.
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
The `HeroTaxReturnService` caches a single `HeroTaxReturn` , tracks changes to that return, and can save or restore it.
2017-03-11 08:44:25 -05:00
It also delegates to the application-wide singleton `HeroService` , which it gets by injection.
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-example path = "hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" header = "src/app/hero-tax-return.service.ts" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
Here is the `HeroTaxReturnComponent` that makes use of `HeroTaxReturnService` .
2017-02-22 13:09:39 -05:00
2017-03-11 08:44:25 -05:00
2018-10-11 07:29:59 -04:00
< code-example path = "hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" header = "src/app/hero-tax-return.component.ts" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2019-02-13 12:50:30 -05:00
The _tax-return-to-edit_ arrives via the `@Input()` property, which is implemented with getters and setters.
2017-02-22 13:09:39 -05:00
The setter initializes the component's own instance of the `HeroTaxReturnService` with the incoming return.
The getter always returns what that service says is the current state of the hero.
The component also asks the service to save and restore this tax return.
2018-05-31 15:02:50 -04:00
This won't work if the service is an application-wide singleton.
Every component would share the same service instance, and each component would overwrite the tax return that belonged to another hero.
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
To prevent this, configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata.
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
< code-example path = "hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" header = "src/app/hero-tax-return.component.ts (providers)" region = "providers" >
< / code-example >
2017-03-27 11:08:53 -04:00
2017-03-11 08:44:25 -05:00
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService` .
Recall that every component _instance_ has its own injector.
2018-05-31 15:02:50 -04:00
Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service, and no tax return gets overwritten.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
2018-07-19 18:00:08 -04:00
< div class = "alert is-helpful" >
2017-03-27 11:08:53 -04:00
2017-02-22 13:09:39 -05:00
The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.
2017-03-11 08:44:25 -05:00
You can review it and download it from the < live-example > < / live-example > .
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Scenario: specialized providers
2018-05-31 15:02:50 -04:00
Another reason to re-provide a service at another level is to substitute a _more specialized_ implementation of that service, deeper in the component tree.
2017-02-22 13:09:39 -05:00
2018-05-31 15:02:50 -04:00
Consider a Car component that depends on several services.
2017-03-11 08:44:25 -05:00
Suppose you configured the root injector (marked as A) with _generic_ providers for
2017-02-22 13:09:39 -05:00
`CarService` , `EngineService` and `TiresService` .
You create a car component (A) that displays a car constructed from these three generic services.
Then you create a child component (B) that defines its own, _specialized_ providers for `CarService` and `EngineService`
2018-03-10 12:14:58 -05:00
that have special capabilities suitable for whatever is going on in component (B).
2017-02-22 13:09:39 -05:00
Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService` .
2017-03-30 15:04:18 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = "generated/images/guide/dependency-injection/car-components.png" alt = "car components" >
< / div >
2017-02-22 13:09:39 -05:00
Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
When you resolve an instance of `Car` at the deepest component (C),
its injector produces an instance of `Car` resolved by injector (C) with an `Engine` resolved by injector (B) and
`Tires` resolved by the root injector (A).
2017-03-30 15:04:18 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = "generated/images/guide/dependency-injection/injector-tree.png" alt = "car injector tree" >
< / div >
2017-02-22 13:09:39 -05:00
2019-02-13 12:50:30 -05:00
< hr / >
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
## More on dependency injection
2017-03-27 11:08:53 -04:00
2019-02-13 12:50:30 -05:00
For more information on Angular dependency injection, see the [DI Providers ](guide/dependency-injection-providers ) and [DI in Action ](guide/dependency-injection-in-action ) guides.