Hierarchical dependency injectors

The Angular dependency injection system is hierarchical. There is a tree of injectors that parallels an app's component tree. You can reconfigure the injectors at any level of that component tree.

Where to configure providers

You can configure providers for different injectors in the injector hierarchy. An internal platform-level injector is shared by all running apps. The AppModule injector is the root of an app-wide injector hierarchy, and within an NgModule, directive-level injectors follow the structure of the component hierarchy.

The choices you make about where to configure providers lead to differences in the final bundle size, service scope, and service lifetime.

When you specify providers in the @Injectable() decorator of the service itself (typically at the app root level), optimization tools such as those used by the CLI's production builds can perform tree shaking, which removes services that aren't used by your app. Tree shaking results in smaller bundle sizes.

You're likely to inject UserService in many places throughout the app and will want to inject the same service instance every time. Providing UserService through the root injector is a good choice, and is the default that the Angular CLI uses when you generate service for your app.

NgModule-level providers can be specified with @NgModule() providers metadata option or in the @Injectable() providedIn option (with some module other than the root AppModule).

@Injectable-level configuration

The @Injectable() decorator identifies every service class. The providedIn metadata option for a service class configures a specific injector (typically root) to use the decorated class as a provider of the service. When an injectable class provides its own service to the root injector, the service is available anywhere the class is imported. This is illustrated below.

TypeScript Code:

import { Injectable } from '@angular/core';

  providedIn: 'root',
export class HeroService {
  constructor() { }

Live Demo:

It is just a code snippet explaining a particular concept and may not have any output

See the Pen @injectable-level_configuration.ts by w3resource (@w3resource) on CodePen.

@NgModule-level injectors

You can configure a provider at the module level using the providers metadata option for a non-root NgModule, in order to limit the scope of the provider to that module. This is the equivalent of specifying the non-root module in the @Injectable() metadata, except that the service provided via providers is not tree-shakable.

You generally don't need to specify AppModule with providedIn, because the app's root injector is the AppModule injector. However, if you configure a app-wide provider in the @NgModule() metadata for 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. Example:

providers: [
  { provide: LocationStrategy, useClass: HashLocationStrategy }

@Component-level injectors

Individual components within a NgModule have their own injectors. You can limit the scope of a provider to a component and its children by configuring the provider at the component level using the @Component metadata.

TypeScript Code:

import { Component } from '@angular/core';

import { StudentService } from './student.service';

  selector: 'app-students',
  providers: [ StudentService ],
  template: `
export class StudentsComponent { }

Live Demo:

It is just a code snippet explaining a particular concept and may not have any output

See the Pen @component-level_injectors.ts by w3resource (@w3resource) on CodePen.

Element injectors

An injector does not actually belong to a component, but rather to the component instance's anchor element in the DOM. A different component instance on a different DOM element uses a different injector.

Components are a special type of directive, and the providers property of @Component() is inherited from @Directive(). Directives can also have dependencies and you can configure providers in their @Directive() metadata. When you configure a provider for a component or directive using the providers property, that provider belongs to the injector for the anchor DOM element. Components and directives on the same element share an injector.

Previous: Dependency Providers
Next: Navigate the component tree with DI

Follow us on Facebook and Twitter for latest update.