w3resource

Dependency Injection in Angular

Dependency injection (DI), is an important application design pattern. Angular has its own DI framework, which is typically used in the design of Angular applications to increase their efficiency and modularity.

Dependencies are services or objects that a class needs to perform its function. DI is a coding pattern in which a class asks for dependencies from external sources rather than creating them itself.

In Angular, the DI framework provides declared dependencies to a class when that class is instantiated. This guide explains how DI works in Angular, and how you use it to make your apps flexible, efficient, and robust, as well as testable and maintainable.

Example consider the students component below:

TypeScript Code:

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

@Component({
  selector: 'app-students',
  template: `
    <h2>Students</h2>
    <app-student-list></app-student-list>
  `
})
export class StudentsComponent { }

Live Demo:

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

See the Pen DI_studentscomponent.js by w3resource (@w3resource) on CodePen.


And the student-list component as described below:

TypeScript Code:

import { Component }   from '@angular/core';
import { STUDENTS }      from './mock-students';

@Component({
  selector: 'app-student-list',
  template: `
    <div *ngFor="let student of students">
      {{student.id}} - {{student.name}}
    </div>
  `
})
export class StudentListComponent {
  students = STUDENTS;
}

Live Demo:

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

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


StudentsComponent is the top-level student's component. Its only purpose is to display StudentListComponent, which displays a list of student names.

This version of the StudentListComponent gets students from the STUDENTS array, an in-memory collection defined in a separate mock-students file.

student-list.component.ts

export class StudentListComponent {
  students = STUDENTS;
}

This approach works for prototyping but is not robust or maintainable. As soon as you try to test this component or get students from a remote server, you have to change the implementation of StudentsListComponent and replace every use of the STUDENTS mock data.

Create and register an injectable service

The DI framework lets you supply data to a component from an injectable service class, defined in its own file. To demonstrate, we'll create an injectable service class that provides a list of students, and register that class as a provider of that service.

Having multiple classes in the same file can be confusing. It is generally recommended that you define components and services in separate files.

Create an injectable service class

The Angular CLI can generate a new StudentService class in the src/app/students folder with this command.

ng generate service students/student

The command creates the following StudentService skeleton.

import { Injectable } from '@angular/core';
@Injectable({
  providedIn: 'root',
})
export class StudentService {
  constructor() { }
}

The @Injectable() is an essential ingredient in every Angular service definition. The rest of the class has been written to expose a getStudents method that returns the same mock data as before. (A real app would probably get its data asynchronously from a remote server, but we'll ignore that to focus on the mechanics of injecting the service.)

Configure an injector with a service provider

You can configure injectors with providers at different levels of your app, by setting a metadata value in one of three places:

  • In the @Injectable() decorator for the service itself.
  • In the @NgModule() decorator for an NgModule.
  • In the @Component() decorator for a component.

The @Injectable() decorator has the providedIn metadata option, where you can specify the provider of the decorated service class with the root injector, or with the injector for a specific NgModule.

The @NgModule() and @Component() decorators have the providers metadata option, where you can configure providers for NgModule-level or component-level injectors.

Injecting services

In order for StudentListComponent to get Students from StudentService, it needs to ask for StudentService to be injected, rather than creating its own StudentService instance with new.

You can tell Angular to inject a dependency in a component's constructor by specifying a constructor parameter with the dependency type. Here's the StudentListComponent constructor, asking for the StudentService to be injected.

constructor(StudentService: StudentService)

Of course, StudentListComponent should do something with the injected StudentService. Here's the revised component, making use of the injected service.

TypeScript Code:

import { Component }   from '@angular/core';
import { Hero }        from './student';
import { HeroService } from './student.service';

@Component({
  selector: 'app-student-list',
  template: `
    <div *ngFor="let student of studente">
      {{student.id}} - {{student.name}}
    </div>
  `
})
export class StudentListComponent {
  students: Student[];

  constructor(studentService: StudentService) {
    this.students = studentService.getStudent();
  }
}

Live Demo:

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

See the Pen DI_studentListwithDI.ts by w3resource (@w3resource) on CodePen.


Previous: NgModule FAQs
Next: Dependency Providers