{ "id": "guide/hierarchical-dependency-injection", "title": "Hierarchical injectors", "contents": "\n\n\n
\n mode_edit\n
\n\n\n
\n

Hierarchical injectorslink

\n

Injectors in Angular have rules that you can leverage to\nachieve the desired visibility of injectables in your apps.\nBy understanding these rules, you can determine in which\nNgModule, Component or Directive you should declare a provider.

\n

Two injector hierarchieslink

\n

There are two injector hierarchies in Angular:

\n
    \n
  1. ModuleInjector hierarchyβ€”configure a ModuleInjector\nin this hierarchy using an @NgModule() or @Injectable() annotation.
  2. \n
  3. ElementInjector hierarchyβ€”created implicitly at each\nDOM element. An ElementInjector is empty by default\nunless you configure it in the providers property on\n@Directive() or @Component().
  4. \n
\n\n

ModuleInjectorlink

\n

The ModuleInjector can be configured in one of two ways:

\n\n
\n

Tree-shaking and @Injectable()link

\n

Using the @Injectable() providedIn property is preferable\nto the @NgModule() providers\narray because with @Injectable() providedIn, optimization\ntools can perform\ntree-shaking, which removes services that your app isn't\nusing and results in smaller bundle sizes.

\n

Tree-shaking is especially useful for a library\nbecause the application which uses the library may not have\na need to inject it. Read more\nabout tree-shakable providers\nin Introduction to services and dependency injection.

\n
\n

ModuleInjector is configured by the @NgModule.providers and\nNgModule.imports property. ModuleInjector is a flattening of\nall of the providers arrays which can be reached by following the\nNgModule.imports recursively.

\n

Child ModuleInjectors are created when lazy loading other @NgModules.

\n

Provide services with the providedIn property of @Injectable() as follows:

\n\nimport { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root' // <--provides this service in the root ModuleInjector\n})\nexport class ItemService {\n name = 'telephone';\n}\n\n

The @Injectable() decorator identifies a service class.\nThe providedIn property configures a specific ModuleInjector,\nhere root, which makes the service available in the root ModuleInjector.

\n

Platform injectorlink

\n

There are two more injectors above root, an\nadditional ModuleInjector and NullInjector().

\n

Consider how Angular bootstraps the app with the\nfollowing in main.ts:

\n\nplatformBrowserDynamic().bootstrapModule(AppModule).then(ref => {...})\n\n

The bootstrapModule() method creates a child injector of\nthe platform injector which is configured by the AppModule.\nThis is the root ModuleInjector.

\n

The platformBrowserDynamic() method creates an injector\nconfigured by a PlatformModule, which contains platform-specific\ndependencies. This allows multiple apps to share a platform\nconfiguration.\nFor example, a browser has only one URL bar, no matter how\nmany apps you have running.\nYou can configure additional platform-specific providers at the\nplatform level by supplying extraProviders using the platformBrowser() function.

\n

The next parent injector in the hierarchy is the NullInjector(),\nwhich is the top of the tree. If you've gone so far up the tree\nthat you are looking for a service in the NullInjector(), you'll\nget an error unless you've used @Optional() because ultimately,\neverything ends at the NullInjector() and it returns an error or,\nin the case of @Optional(), null. For more information on\n@Optional(), see the @Optional() section of this guide.

\n

The following diagram represents the relationship between the\nroot ModuleInjector and its parent injectors as the\nprevious paragraphs describe.

\n
\n \"NullInjector,\n
\n

While the name root is a special alias, other ModuleInjectors\ndon't have aliases. You have the option to create ModuleInjectors\nwhenever a dynamically loaded component is created, such as with\nthe Router, which will create child ModuleInjectors.

\n

All requests forward up to the root injector, whether you configured it\nwith the bootstrapModule() method, or registered all providers\nwith root in their own services.

\n
\n

@Injectable() vs. @NgModule()link

\n

If you configure an app-wide provider in the @NgModule() of\nAppModule, it overrides one configured for root in the\n@Injectable() metadata. You can do this to configure a\nnon-default provider of a service that is shared with multiple apps.

\n

Here is an example of the case where the component router\nconfiguration includes\na non-default location strategy\nby listing its provider\nin the providers list of the AppModule.

\n\nproviders: [\n { provide: LocationStrategy, useClass: HashLocationStrategy }\n]\n\n\n
\n

ElementInjectorlink

\n

Angular creates ElementInjectors implicitly for each DOM element.

\n

Providing a service in the @Component() decorator using\nits providers or viewProviders\nproperty configures an ElementInjector.\nFor example, the following TestComponent configures the ElementInjector\nby providing the service as follows:

\n\n@Component({\n ...\n providers: [{ provide: ItemService, useValue: { name: 'lamp' } }]\n})\nexport class TestComponent\n\n
\n

Note: Please see the\nresolution rules\nsection to understand the relationship between the ModuleInjector tree and\nthe ElementInjector tree.

\n
\n

When you provide services in a component, that service is available via\nthe ElementInjector at that component instance.\nIt may also be visible at\nchild component/directives based on visibility rules described in the resolution rules section.

\n

When the component instance is destroyed, so is that service instance.

\n

@Directive() and @Component()link

\n

A component is a special type of directive, which means that\njust as @Directive() has a providers property, @Component() does too.\nThis means that directives as well as components can configure\nproviders, using the providers property.\nWhen you configure a provider for a component or directive\nusing the providers property,\nthat provider belongs to the ElementInjector of that component or\ndirective.\nComponents and directives on the same element share an injector.

\n\n

Resolution ruleslink

\n

When resolving a token for a component/directive, Angular\nresolves it in two phases:

\n
    \n
  1. Against the ElementInjector hierarchy (its parents)
  2. \n
  3. Against the ModuleInjector hierarchy (its parents)
  4. \n
\n

When a component declares a dependency, Angular tries to satisfy that\ndependency with its own ElementInjector.\nIf the component's injector lacks the provider, it passes the request\nup to its parent component's ElementInjector.

\n

The requests keep forwarding up until Angular finds an injector that can\nhandle the request or runs out of ancestor ElementInjectors.

\n

If Angular doesn't find the provider in any ElementInjectors,\nit goes back to the element where the request originated and looks\nin the ModuleInjector hierarchy.\nIf Angular still doesn't find the provider, it throws an error.

\n

If you have registered a provider for the same DI token at\ndifferent levels, the first one Angular encounters is the one\nit uses to resolve the dependency. If, for example, a provider\nis registered locally in the component that needs a service,\nAngular doesn't look for another provider of the same service.

\n

Resolution modifierslink

\n

Angular's resolution behavior can be modified with @Optional(), @Self(),\n@SkipSelf() and @Host(). Import each of them from @angular/core\nand use each in the component class constructor when you inject your service.

\n

For a working app showcasing the resolution modifiers that\nthis section covers, see the resolution modifiers example.

\n

Types of modifierslink

\n

Resolution modifiers fall into three categories:

\n
    \n
  1. What to do if Angular doesn't find what you're\nlooking for, that is @Optional()
  2. \n
  3. Where to start looking, that is @SkipSelf()
  4. \n
  5. Where to stop looking, @Host() and @Self()
  6. \n
\n

By default, Angular always starts at the current Injector and keeps\nsearching all the way up. Modifiers allow you to change the starting\n(self) or ending location.

\n

Additionally, you can combine all of the modifiers except @Host() and @Self() and of course @SkipSelf() and @Self().

\n\n

@Optional()link

\n

@Optional() allows Angular to consider a service you inject to be optional.\nThis way, if it can't be resolved at runtime, Angular simply\nresolves the service as null, rather than throwing an error. In\nthe following example, the service, OptionalService, isn't provided in\nthe service, @NgModule(), or component class, so it isn't available\nanywhere in the app.

\n\nexport class OptionalComponent {\n constructor(@Optional() public optional?: OptionalService) {}\n}\n\n\n

@Self()link

\n

Use @Self() so that Angular will only look at the ElementInjector for the current component or directive.

\n

A good use case for @Self() is to inject a service but only if it is\navailable on the current host element. To avoid errors in this situation,\ncombine @Self() with @Optional().

\n

For example, in the following SelfComponent, notice\nthe injected LeafService in\nthe constructor.

\n\n@Component({\n selector: 'app-self-no-data',\n templateUrl: './self-no-data.component.html',\n styleUrls: ['./self-no-data.component.css']\n})\nexport class SelfNoDataComponent {\n constructor(@Self() @Optional() public leaf?: LeafService) { }\n}\n\n\n\n

In this example, there is a parent provider and injecting the\nservice will return the value, however, injecting the service\nwith @Self() and @Optional() will return null because\n@Self() tells the injector to stop searching in the current\nhost element.

\n

Another example shows the component class with a provider\nfor FlowerService. In this case, the injector looks no further\nthan the current ElementInjector because it finds the FlowerService and returns the yellow flower 🌼.

\n\n@Component({\n selector: 'app-self',\n templateUrl: './self.component.html',\n styleUrls: ['./self.component.css'],\n providers: [{ provide: FlowerService, useValue: { emoji: '🌼' } }]\n\n})\nexport class SelfComponent {\n constructor(@Self() public flower: FlowerService) {}\n}\n\n\n

@SkipSelf()link

\n

@SkipSelf() is the opposite of @Self(). With @SkipSelf(), Angular\nstarts its search for a service in the parent ElementInjector, rather than\nin the current one. So if the parent ElementInjector were using the value 🌿 (fern)\nfor emoji , but you had 🍁 (maple leaf) in the component's providers array,\nAngular would ignore 🍁 (maple leaf) and use 🌿 (fern).

\n

To see this in code, assume that the following value for emoji is what the parent component were using, as in this service:

\n\nexport class LeafService {\n emoji = '🌿';\n}\n\n\n

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():

\n\n@Component({\n selector: 'app-skipself',\n templateUrl: './skipself.component.html',\n styleUrls: ['./skipself.component.css'],\n // Angular would ignore this LeafService instance\n providers: [{ provide: LeafService, useValue: { emoji: '🍁' } }]\n})\nexport class SkipselfComponent {\n // Use @SkipSelf() in the constructor\n constructor(@SkipSelf() public leaf: LeafService) { }\n}\n\n\n

In this case, the value you'd get for emoji would be 🌿 (fern), not 🍁 (maple leaf).

\n

@SkipSelf() with @Optional()link

\n

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.

\n\nclass Person {\n constructor(@Optional() @SkipSelf() parent?: Person) {}\n}\n\n

@Host()link

\n

@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:

\n\n@Component({\n selector: 'app-host',\n templateUrl: './host.component.html',\n styleUrls: ['./host.component.css'],\n // provide the service\n providers: [{ provide: FlowerService, useValue: { emoji: '🌼' } }]\n})\nexport class HostComponent {\n // use @Host() in the constructor when injecting the service\n constructor(@Host() @Optional() public flower?: FlowerService) { }\n\n}\n\n\n

Since HostComponent has @Host() in its constructor, no\nmatter what the parent of HostComponent might have as a\nflower.emoji value,\nthe HostComponent will use 🌼 (yellow flower).

\n

Logical structure of the templatelink

\n

When you provide services in the component class, services are\nvisible within the ElementInjector tree relative to where\nand how you provide those services.

\n

Understanding the underlying logical structure of the Angular\ntemplate will give you a foundation for configuring services\nand in turn control their visibility.

\n

Components are used in your templates, as in the following example:

\n\n<app-root>\n <app-child></app-child>\n</app-root>\n\n
\n

Note: Usually, you declare the components and their\ntemplates in separate files. For the purposes of understanding\nhow the injection system works, it is useful to look at them\nfrom the point of view of a combined logical tree. The term\nlogical distinguishes it from the render tree (your application\nDOM tree). To mark the locations of where the component\ntemplates are located, this guide uses the <#VIEW>\npseudo element, which doesn't actually exist in the render tree\nand is present for mental model purposes only.

\n
\n

The following is an example of how the <app-root> and <app-child> view trees are combined into a single logical tree:

\n\n<app-root>\n <#VIEW>\n <app-child>\n <#VIEW>\n ...content goes here...\n </#VIEW>\n </app-child>\n <#VIEW>\n</app-root>\n\n

Understanding the idea of the <#VIEW> demarcation is especially significant when you configure services in the component class.

\n

Providing services in @Component()link

\n

How you provide services via an @Component() (or @Directive())\ndecorator determines their visibility. The following sections\ndemonstrate providers and viewProviders along with ways to\nmodify service visibility with @SkipSelf() and @Host().

\n

A component class can provide services in two ways:

\n
    \n
  1. with a providers array
  2. \n
\n\n@Component({\n ...\n providers: [\n {provide: FlowerService, useValue: {emoji: '🌺'}}\n ]\n})\n\n
    \n
  1. with a viewProviders array
  2. \n
\n\n@Component({\n ...\n viewProviders: [\n {provide: AnimalService, useValue: {emoji: '🐢'}}\n ]\n})\n\n

To understand how the providers and viewProviders influence service\nvisibility differently, the following sections build\na \nstep-by-step and compare the use of providers and viewProviders\nin code and a logical tree.

\n
\n

NOTE: In the logical tree, you'll see @Provide, @Inject, and\n@NgModule, which are not real HTML attributes but are here to demonstrate\nwhat is going on under the hood.

\n\n
\n

Example app structurelink

\n

The example app has a FlowerService provided in root with an emoji\nvalue of 🌺 (red hibiscus).

\n\n@Injectable({\n providedIn: 'root'\n})\nexport class FlowerService {\n emoji = '🌺';\n}\n\n\n

Consider a simple app with only an AppComponent and a ChildComponent.\nThe most basic rendered view would look like nested HTML elements such as\nthe following:

\n\n<app-root> <!-- AppComponent selector -->\n <app-child> <!-- ChildComponent selector -->\n </app-child>\n</app-root>\n\n

However, behind the scenes, Angular uses a logical view\nrepresentation as follows when resolving injection requests:

\n\n<app-root> <!-- AppComponent selector -->\n <#VIEW>\n <app-child> <!-- ChildComponent selector -->\n <#VIEW>\n </#VIEW>\n </app-child>\n </#VIEW>\n</app-root>\n\n

The <#VIEW> here represents an instance of a template.\nNotice that each component has its own <#VIEW>.

\n

Knowledge of this structure can inform how you provide and\ninject your services, and give you complete control of service visibility.

\n

Now, consider that <app-root> simply injects the FlowerService:

\n\nexport class AppComponent {\n constructor(public flower: FlowerService) {}\n}\n\n\n

Add a binding to the <app-root> template to visualize the result:

\n\n<p>Emoji from FlowerService: {{flower.emoji}}</p>\n\n\n

The output in the view would be:

\n\nEmoji from FlowerService: 🌺\n\n

In the logical tree, this would be represented as follows:

\n\n<app-root @NgModule(AppModule)\n @Inject(FlowerService) flower=>\"🌺\">\n <#VIEW>\n <p>Emoji from FlowerService: {{flower.emoji}} (🌺)</p>\n <app-child>\n <#VIEW>\n </#VIEW>\n </app-child>\n </#VIEW>\n</app-root>\n\n

When <app-root> requests the FlowerService, it is the injector's job\nto resolve the FlowerService token. The resolution of the token happens\nin two phases:

\n
    \n
  1. The injector determines the starting location in the logical tree and\nan ending location of the search. The injector begins with the starting\nlocation and looks for the token at each level in the logical tree. If\nthe token is found it is returned.
  2. \n
  3. If the token is not found, the injector looks for the closest\nparent @NgModule() to delegate the request to.
  4. \n
\n

In the example case, the constraints are:

\n
    \n
  1. Start with <#VIEW> belonging to <app-root> and end with <app-root>.
  2. \n
\n\n
    \n
  1. The AppModule acts as the fallback injector when the\ninjection token can't be found in the ElementInjectors.
  2. \n
\n

Using the providers arraylink

\n

Now, in the ChildComponent class, add a provider for FlowerService\nto demonstrate more complex resolution rules in the upcoming sections:

\n\n@Component({\n selector: 'app-child',\n templateUrl: './child.component.html',\n styleUrls: ['./child.component.css'],\n // use the providers array to provide a service\n providers: [{ provide: FlowerService, useValue: { emoji: '🌻' } }]\n})\n\nexport class ChildComponent {\n // inject the service\n constructor( public flower: FlowerService) { }\n}\n\n\n\n

Now that the FlowerService is provided in the @Component() decorator,\nwhen the <app-child> requests the service, the injector has only to look\nas far as the <app-child>'s own ElementInjector. It won't have to\ncontinue the search any further through the injector tree.

\n

The next step is to add a binding to the ChildComponent template.

\n\n<p>Emoji from FlowerService: {{flower.emoji}}</p>\n\n\n

To render the new values, add <app-child> to the bottom of\nthe AppComponent template so the view also displays the sunflower:

\n\nChild Component\nEmoji from FlowerService: 🌻\n\n

In the logical tree, this would be represented as follows:

\n\n<app-root @NgModule(AppModule)\n @Inject(FlowerService) flower=>\"🌺\">\n <#VIEW>\n <p>Emoji from FlowerService: {{flower.emoji}} (🌺)</p>\n <app-child @Provide(FlowerService=\"🌻\")\n @Inject(FlowerService)=>\"🌻\"> <!-- search ends here -->\n <#VIEW> <!-- search starts here -->\n <h2>Parent Component</h2>\n <p>Emoji from FlowerService: {{flower.emoji}} (🌻)</p>\n </#VIEW>\n </app-child>\n </#VIEW>\n</app-root>\n\n

When <app-child> requests the FlowerService, the injector begins\nits search at the <#VIEW> belonging to <app-child> (<#VIEW> is\nincluded because it is injected from @Component()) and ends with\n<app-child>. In this case, the FlowerService is resolved in the\n<app-child>'s providers array with sunflower 🌻. The injector doesn't\nhave to look any further in the injector tree. It stops as soon as it\nfinds the FlowerService and never sees the 🌺 (red hibiscus).

\n\n

Using the viewProviders arraylink

\n

Use the viewProviders array as another way to provide services in the\n@Component() decorator. Using viewProviders makes services\nvisible in the <#VIEW>.

\n
\n

The steps are the same as using the providers array,\nwith the exception of using the viewProviders array instead.

\n

For step-by-step instructions, continue with this section. If you can\nset it up on your own, skip ahead to Modifying service availability.

\n
\n

The example app features a second service, the AnimalService to\ndemonstrate viewProviders.

\n

First, create an AnimalService with an emoji property of 🐳 (whale):

\n\nimport { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class AnimalService {\n emoji = '🐳';\n}\n\n\n

Following the same pattern as with the FlowerService, inject the\nAnimalService in the AppComponent class:

\n\nexport class AppComponent {\n constructor(public flower: FlowerService, public animal: AnimalService) {}\n}\n\n\n
\n

Note: You can leave all the FlowerService related code in place\nas it will allow a comparison with the AnimalService.

\n
\n

Add a viewProviders array and inject the AnimalService in the\n<app-child> class, too, but give emoji a different value. Here,\nit has a value of 🐢 (puppy).

\n\n@Component({\n selector: 'app-child',\n templateUrl: './child.component.html',\n styleUrls: ['./child.component.css'],\n // provide services\n providers: [{ provide: FlowerService, useValue: { emoji: '🌻' } }],\n viewProviders: [{ provide: AnimalService, useValue: { emoji: '🐢' } }]\n})\n\nexport class ChildComponent {\n // inject service\n constructor( public flower: FlowerService, public animal: AnimalService) { }\n}\n\n\n

Add bindings to the ChildComponent and the AppComponent templates.\nIn the ChildComponent template, add the following binding:

\n\n<p>Emoji from AnimalService: {{animal.emoji}}</p>\n\n\n

Additionally, add the same to the AppComponent template:

\n\n<p>Emoji from AnimalService: {{animal.emoji}}</p>\n\n\n

Now you should see both values in the browser:

\n\nAppComponent\nEmoji from AnimalService: 🐳\n\nChild Component\nEmoji from AnimalService: 🐢\n\n

The logic tree for this example of viewProviders is as follows:

\n\n<app-root @NgModule(AppModule)\n @Inject(AnimalService) animal=>\"🐳\">\n <#VIEW>\n <app-child>\n <#VIEW\n @Provide(AnimalService=\"🐢\")\n @Inject(AnimalService=>\"🐢\")>\n <!-- ^^using viewProviders means AnimalService is available in <#VIEW>-->\n <p>Emoji from AnimalService: {{animal.emoji}} (🐢)</p>\n </#VIEW>\n </app-child>\n </#VIEW>\n</app-root>\n\n

Just as with the FlowerService example, the AnimalService is provided\nin the <app-child> @Component() decorator. This means that since the\ninjector first looks in the ElementInjector of the component, it finds the\nAnimalService value of 🐢 (puppy). It doesn't need to continue searching the\nElementInjector tree, nor does it need to search the ModuleInjector.

\n

providers vs. viewProviderslink

\n

To see the difference between using providers and viewProviders, add\nanother component to the example and call it InspectorComponent.\nInspectorComponent will be a child of the ChildComponent. In\ninspector.component.ts, inject the FlowerService and AnimalService in\nthe constructor:

\n\nexport class InspectorComponent {\n constructor(public flower: FlowerService, public animal: AnimalService) { }\n}\n\n\n

You do not need a providers or viewProviders array. Next, in\ninspector.component.html, add the same markup from previous components:

\n\n<p>Emoji from FlowerService: {{flower.emoji}}</p>\n<p>Emoji from AnimalService: {{animal.emoji}}</p>\n\n\n

Remember to add the InspectorComponent to the AppModule declarations array.

\n\n@NgModule({\n imports: [ BrowserModule, FormsModule ],\n declarations: [ AppComponent, ChildComponent, InspectorComponent ],\n bootstrap: [ AppComponent ],\n providers: []\n})\nexport class AppModule { }\n\n\n

Next, make sure your child.component.html contains the following:

\n\n<p>Emoji from FlowerService: {{flower.emoji}}</p>\n<p>Emoji from AnimalService: {{animal.emoji}}</p>\n\n<div class=\"container\">\n <h3>Content projection</h3>\n\t<ng-content></ng-content>\n</div>\n\n<h3>Inside the view</h3>\n<app-inspector></app-inspector>\n\n\n

The first two lines, with the bindings, are there from previous steps. The\nnew parts are <ng-content> and <app-inspector>. <ng-content> allows\nyou to project content, and <app-inspector> inside the ChildComponent\ntemplate makes the InspectorComponent a child component of\nChildComponent.

\n

Next, add the following to app.component.html to take advantage of content projection.

\n\n<app-child><app-inspector></app-inspector></app-child>\n\n\n

The browser now renders the following, omitting the previous examples\nfor brevity:

\n\n//...Omitting previous examples. The following applies to this section.\n\nContent projection: This is coming from content. Doesn't get to see\npuppy because the puppy is declared inside the view only.\n\nEmoji from FlowerService: 🌻\nEmoji from AnimalService: 🐳\n\nEmoji from FlowerService: 🌻\nEmoji from AnimalService: 🐢\n\n

These four bindings demonstrate the difference between providers\nand viewProviders. Since the 🐢 (puppy) is declared inside the <#VIEW>,\nit isn't visible to the projected content. Instead, the projected\ncontent sees the 🐳 (whale).

\n

The next section though, where InspectorComponent is a child component\nof ChildComponent, InspectorComponent is inside the <#VIEW>, so\nwhen it asks for the AnimalService, it sees the 🐢 (puppy).

\n

The AnimalService in the logical tree would look like this:

\n\n<app-root @NgModule(AppModule)\n @Inject(AnimalService) animal=>\"🐳\">\n <#VIEW>\n <app-child>\n <#VIEW\n @Provide(AnimalService=\"🐢\")\n @Inject(AnimalService=>\"🐢\")>\n <!-- ^^using viewProviders means AnimalService is available in <#VIEW>-->\n <p>Emoji from AnimalService: {{animal.emoji}} (🐢)</p>\n <app-inspector>\n <p>Emoji from AnimalService: {{animal.emoji}} (🐢)</p>\n </app-inspector>\n </#VIEW>\n <app-inspector>\n <#VIEW>\n <p>Emoji from AnimalService: {{animal.emoji}} (🐳)</p>\n </#VIEW>\n </app-inspector>\n </app-child>\n </#VIEW>\n</app-root>\n\n

The projected content of <app-inspector> sees the 🐳 (whale), not\nthe 🐢 (puppy), because the\n🐢 (puppy) is inside the <app-child> <#VIEW>. The <app-inspector> can\nonly see the 🐢 (puppy)\nif it is also within the <#VIEW>.

\n\n

Modifying service visibilitylink

\n

This section describes how to limit the scope of the beginning and\nending ElementInjector using the visibility decorators @Host(),\n@Self(), and @SkipSelf().

\n

Visibility of provided tokenslink

\n

Visibility decorators influence where the search for the injection\ntoken begins and ends in the logic tree. To do this, place\nvisibility decorators at the point of injection, that is, the\nconstructor(), rather than at a point of declaration.

\n

To alter where the injector starts looking for FlowerService, add\n@SkipSelf() to the <app-child> @Inject declaration for the\nFlowerService. This declaration is in the <app-child> constructor\nas shown in child.component.ts:

\n\n constructor(@SkipSelf() public flower : FlowerService) { }\n\n

With @SkipSelf(), the <app-child> injector doesn't look to itself for\nthe FlowerService. Instead, the injector starts looking for the\nFlowerService at the <app-root>'s ElementInjector, where it finds\nnothing. Then, it goes back to the <app-child> ModuleInjector and finds\nthe 🌺 (red hibiscus) value, which is available because the <app-child>\nModuleInjector and the <app-root> ModuleInjector are flattened into one\nModuleInjector. Thus, the UI renders the following:

\n\nEmoji from FlowerService: 🌺\n\n

In a logical tree, this same idea might look like this:

\n\n<app-root @NgModule(AppModule)\n @Inject(FlowerService) flower=>\"🌺\">\n <#VIEW>\n <app-child @Provide(FlowerService=\"🌻\")>\n <#VIEW @Inject(FlowerService, SkipSelf)=>\"🌺\">\n <!-- With SkipSelf, the injector looks to the next injector up the tree -->\n </#VIEW>\n </app-child>\n </#VIEW>\n</app-root>\n\n

Though <app-child> provides the 🌻 (sunflower), the app renders\nthe 🌺 (red hibiscus) because @SkipSelf() causes the current\ninjector to skip\nitself and look to its parent.

\n

If you now add @Host() (in addition to the @SkipSelf()) to the\n@Inject of the FlowerService, the result will be null. This is\nbecause @Host() limits the upper bound of the search to the\n<#VIEW>. Here's the idea in the logical tree:

\n\n<app-root @NgModule(AppModule)\n @Inject(FlowerService) flower=>\"🌺\">\n <#VIEW> <!-- end search here with null-->\n <app-child @Provide(FlowerService=\"🌻\")> <!-- start search here -->\n <#VIEW @Inject(FlowerService, @SkipSelf, @Host, @Optional)=>null>\n </#VIEW>\n </app-parent>\n </#VIEW>\n</app-root>\n\n

Here, the services and their values are the same, but @Host()\nstops the injector from looking any further than the <#VIEW>\nfor FlowerService, so it doesn't find it and returns null.

\n
\n

Note: The example app uses @Optional() so the app does\nnot throw an error, but the principles are the same.

\n
\n

@SkipSelf() and viewProviderslink

\n

The <app-child> currently provides the AnimalService in\nthe viewProviders array with the value of 🐢 (puppy). Because\nthe injector has only to look at the <app-child>'s ElementInjector\nfor the AnimalService, it never sees the 🐳 (whale).

\n

Just as in the FlowerService example, if you add @SkipSelf()\nto the constructor for the AnimalService, the injector won't\nlook in the current <app-child>'s ElementInjector for the\nAnimalService.

\n\nexport class ChildComponent {\n\n// add @SkipSelf()\n constructor(@SkipSelf() public animal : AnimalService) { }\n\n}\n\n

Instead, the injector will begin at the <app-root>\nElementInjector. Remember that the <app-child> class\nprovides the AnimalService in the viewProviders array\nwith a value of 🐢 (puppy):

\n\n@Component({\n selector: 'app-child',\n ...\n viewProviders:\n [{ provide: AnimalService, useValue: { emoji: '🐢' } }]\n})\n\n

The logical tree looks like this with @SkipSelf() in <app-child>:

\n\n <app-root @NgModule(AppModule)\n @Inject(AnimalService=>\"🐳\")>\n <#VIEW><!-- search begins here -->\n <app-child>\n <#VIEW\n @Provide(AnimalService=\"🐢\")\n @Inject(AnimalService, SkipSelf=>\"🐳\")>\n <!--Add @SkipSelf -->\n </#VIEW>\n </app-child>\n </#VIEW>\n </app-root>\n\n

With @SkipSelf() in the <app-child>, the injector begins its\nsearch for the AnimalService in the <app-root> ElementInjector\nand finds 🐳 (whale).

\n

@Host() and viewProviderslink

\n

If you add @Host() to the constructor for AnimalService, the\nresult is 🐢 (puppy) because the injector finds the AnimalService\nin the <app-child> <#VIEW>. Here is the viewProviders array\nin the <app-child> class and @Host() in the constructor:

\n\n@Component({\n selector: 'app-child',\n ...\n viewProviders:\n [{ provide: AnimalService, useValue: { emoji: '🐢' } }]\n\n})\nexport class ChildComponent {\n constructor(@Host() public animal : AnimalService) { }\n}\n\n

@Host() causes the injector to look until it encounters the edge of the <#VIEW>.

\n\n <app-root @NgModule(AppModule)\n @Inject(AnimalService=>\"🐳\")>\n <#VIEW>\n <app-child>\n <#VIEW\n @Provide(AnimalService=\"🐢\")\n @Inject(AnimalService, @Host=>\"🐢\")> <!-- @Host stops search here -->\n </#VIEW>\n </app-child>\n </#VIEW>\n </app-root>\n\n

Add a viewProviders array with a third animal, πŸ¦” (hedgehog), to the\napp.component.ts @Component() metadata:

\n\n@Component({\n selector: 'app-root',\n templateUrl: './app.component.html',\n styleUrls: [ './app.component.css' ],\n viewProviders: [{ provide: AnimalService, useValue: { emoji: 'πŸ¦”' } }]\n})\n\n

Next, add @SkipSelf() along with @Host() to the constructor for the\nAnimal Service in child.component.ts. Here are @Host()\nand @SkipSelf() in the <app-child>\nconstructor :

\n\nexport class ChildComponent {\n\n constructor(\n @Host() @SkipSelf() public animal : AnimalService) { }\n\n}\n\n

When @Host() and SkipSelf() were applied to the FlowerService,\nwhich is in the providers array, the result was null because\n@SkipSelf() starts its search in the <app-child> injector, but\n@Host() stops searching at <#VIEW>β€”where there is no\nFlowerService. In the logical tree, you can see that the\nFlowerService is visible in <app-child>, not its <#VIEW>.

\n

However, the AnimalService, which is provided in the\nAppComponent viewProviders array, is visible.

\n

The logical tree representation shows why this is:

\n\n<app-root @NgModule(AppModule)\n @Inject(AnimalService=>\"🐳\")>\n <#VIEW @Provide(AnimalService=\"πŸ¦”\")\n @Inject(AnimalService, @SkipSelf, @Host, @Optional)=>\"πŸ¦”\">\n <!-- ^^@SkipSelf() starts here, @Host() stops here^^ -->\n <app-child>\n <#VIEW @Provide(AnimalService=\"🐢\")\n @Inject(AnimalService, @SkipSelf, @Host, @Optional)=>\"🐢\">\n <!-- Add @SkipSelf ^^-->\n </#VIEW>\n </app-child>\n </#VIEW>\n</app-root>\n\n

@SkipSelf(), causes the injector to start its search for\nthe AnimalService at the <app-root>, not the <app-child>,\nwhere the request originates, and @Host() stops the search\nat the <app-root> <#VIEW>. Since AnimalService is\nprovided via the viewProviders array, the injector finds πŸ¦”\n(hedgehog) in the <#VIEW>.

\n\n

ElementInjector use case exampleslink

\n

The ability to configure one or more providers at different levels\nopens up useful possibilities.\nFor a look at the following scenarios in a working app, see the heroes use case examples.

\n

Scenario: service isolationlink

\n

Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.\nFor example, the guide sample includes a VillainsListComponent that displays a list of villains.\nIt gets those villains from a VillainsService.

\n

If you provided VillainsService in the root AppModule\n(where you registered the HeroesService),\nthat would make the VillainsService visible everywhere in the\napplication, including the Hero workflows. If you later\nmodified the VillainsService, you could break something in a\nhero component somewhere.

\n

Instead, you can provide the VillainsService in the providers metadata of the VillainsListComponent like this:

\n\n@Component({\n selector: 'app-villains-list',\n templateUrl: './villains-list.component.html',\n providers: [ VillainsService ]\n})\n\n\n

By providing VillainsService in the VillainsListComponent metadata and nowhere else,\nthe service becomes available only in the VillainsListComponent and its sub-component tree.

\n

VillainService is a singleton with respect to VillainsListComponent\nbecause that is where it is declared. As long as VillainsListComponent\ndoes not get destroyed it will be the same instance of VillainService\nbut if there are multilple instances of VillainsListComponent, then each\ninstance of VillainsListComponent will have its own instance of VillainService.

\n

Scenario: multiple edit sessionslink

\n

Many applications allow users to work on several open tasks at the same time.\nFor example, in a tax preparation application, the preparer could be working on several tax returns,\nswitching from one to the other throughout the day.

\n

This guide demonstrates that scenario with an example in the Tour of Heroes theme.\nImagine an outer HeroListComponent that displays a list of super heroes.

\n

To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return.\nEach selected hero tax return opens in its own component and multiple returns can be open at the same time.

\n

Each tax return component has the following characteristics:

\n\n
\n \"Heroes\n
\n

Suppose that the HeroTaxReturnComponent had logic to manage and restore changes.\nThat would be a pretty easy task for a simple hero tax return.\nIn the real world, with a rich tax return data model, the change management would be tricky.\nYou could delegate that management to a helper service, as this example does.

\n

The HeroTaxReturnService caches a single HeroTaxReturn, tracks changes to that return, and can save or restore it.\nIt also delegates to the application-wide singleton HeroService, which it gets by injection.

\n\nimport { Injectable } from '@angular/core';\nimport { HeroTaxReturn } from './hero';\nimport { HeroesService } from './heroes.service';\n\n@Injectable()\nexport class HeroTaxReturnService {\n private currentTaxReturn: HeroTaxReturn;\n private originalTaxReturn: HeroTaxReturn;\n\n constructor(private heroService: HeroesService) { }\n\n set taxReturn(htr: HeroTaxReturn) {\n this.originalTaxReturn = htr;\n this.currentTaxReturn = htr.clone();\n }\n\n get taxReturn(): HeroTaxReturn {\n return this.currentTaxReturn;\n }\n\n restoreTaxReturn() {\n this.taxReturn = this.originalTaxReturn;\n }\n\n saveTaxReturn() {\n this.taxReturn = this.currentTaxReturn;\n this.heroService.saveTaxReturn(this.currentTaxReturn).subscribe();\n }\n}\n\n\n\n

Here is the HeroTaxReturnComponent that makes use of HeroTaxReturnService.

\n\nimport { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { HeroTaxReturn } from './hero';\nimport { HeroTaxReturnService } from './hero-tax-return.service';\n\n@Component({\n selector: 'app-hero-tax-return',\n templateUrl: './hero-tax-return.component.html',\n styleUrls: [ './hero-tax-return.component.css' ],\n providers: [ HeroTaxReturnService ]\n})\nexport class HeroTaxReturnComponent {\n message = '';\n\n @Output() close = new EventEmitter<void>();\n\n get taxReturn(): HeroTaxReturn {\n return this.heroTaxReturnService.taxReturn;\n }\n\n @Input()\n set taxReturn(htr: HeroTaxReturn) {\n this.heroTaxReturnService.taxReturn = htr;\n }\n\n constructor(private heroTaxReturnService: HeroTaxReturnService) { }\n\n onCanceled() {\n this.flashMessage('Canceled');\n this.heroTaxReturnService.restoreTaxReturn();\n }\n\n onClose() { this.close.emit(); }\n\n onSaved() {\n this.flashMessage('Saved');\n this.heroTaxReturnService.saveTaxReturn();\n }\n\n flashMessage(msg: string) {\n this.message = msg;\n setTimeout(() => this.message = '', 500);\n }\n}\n\n\n\n

The tax-return-to-edit arrives via the @Input() property, which is implemented with getters and setters.\nThe setter initializes the component's own instance of the HeroTaxReturnService with the incoming return.\nThe getter always returns what that service says is the current state of the hero.\nThe component also asks the service to save and restore this tax return.

\n

This won't work if the service is an application-wide singleton.\nEvery component would share the same service instance, and each component would overwrite the tax return that belonged to another hero.

\n

To prevent this, configure the component-level injector of HeroTaxReturnComponent to provide the service, using the providers property in the component metadata.

\n\nproviders: [ HeroTaxReturnService ]\n\n\n

The HeroTaxReturnComponent has its own provider of the HeroTaxReturnService.\nRecall that every component instance has its own injector.\nProviding 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.

\n
\n

The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.\nYou can review it and download it from the .

\n
\n

Scenario: specialized providerslink

\n

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.

\n

Consider a Car component that depends on several services.\nSuppose you configured the root injector (marked as A) with generic providers for\nCarService, EngineService and TiresService.

\n

You create a car component (A) that displays a car constructed from these three generic services.

\n

Then you create a child component (B) that defines its own, specialized providers for CarService and EngineService\nthat have special capabilities suitable for whatever is going on in component (B).

\n

Component (B) is the parent of another component (C) that defines its own, even more specialized provider for CarService.

\n
\n \"car\n
\n

Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.

\n

When you resolve an instance of Car at the deepest component (C),\nits injector produces an instance of Car resolved by injector (C) with an Engine resolved by injector (B) and\nTires resolved by the root injector (A).

\n
\n \"car\n
\n

More on dependency injectionlink

\n

For more information on Angular dependency injection, see the DI Providers and DI in Action guides.

\n\n \n
\n\n\n" }