Utiliser un service Angular avec l’injection de dépendance

La technique pour utiliser un service Angular dans son application s’appelle l’injection de dépendance. Comment l’utiliser ? Quels sont les points de vigilance ?

ATTENTION. N’instanciez pas le service vous-même

Que vous souhaitiez utiliser un service que vous avez créé ou un service d’Angular, une erreur serait de l’instancier vous-même.

Par exemple, dans le code ci-dessous, j’importe la classe du service, puis je l’instancie avec new MyService().

import { Component, OnInit } from '@angular/core';
import { MyService } from './some/path';

@Component({ ... })
export class AppComponent implements OnInit {
  ngOnInit() {
    const s = new MyService();  // ERREUR, ne pas faire ça
  }
}

C’est une erreur. Pour qu’un service soit un singleton, c’est à dire qu’il n’en existe qu’une seule instance, il faut laisser à Angular la responsabilité de gérer le service : Angular instancie le service à la première utilisation ; les fois suivantes, il réutilise l’instance créée précédemment.

De plus, le service pourrait lui-même avoir des dépendances. Cela commencerait à devenir compliqué si nous devions instancier manuellement les dépendances de notre service, qui ont peut-être à leur tour des dépendances…

C’est pour cela qu’on passe par l’injection de dépendance, un mécanisme qui laisse Angular gérer l’instanciation des services.

Utiliser un service custom avec l’injection de dépendance

Pour utiliser un service que vous avez créé, il suffit de typer un paramètre de constructeur avec la classe de votre service.

Par exemple, si je veux utiliser mon service AuthService dans LoginComponent, j’écrirai :

import { Component, OnInit } from '@angular/core';
import { AuthService } from './services/auth.service';

@Component({ ... })
export class LoginComponent implements OnInit {

  constructor(authService: AuthService) {  // Injection de dépendance
    // Ici, `authService` contient une instance du service
  }

}

Points-clé de la syntaxe de l’injection de dépendance :

  • Elle porte sur les arguments de constructeur d’une classe Angular.
  • Il faut typer chaque argument avec la classe du service qu’on veut injecter dedans.

Quand Angular rencontre cette syntaxe, il instancie le service AuthService (ou se procure l’instance existante si elle existe déjà) et il copie l’instance dans l’argument authService du constructeur.

Le souci, c’est que le service n’est utilisable que dans le constructeur. On combine donc souvent cette syntaxe avec celle des propriétés-paramètres), c. à d. qu’on ajoute private devant l’argument pour le transformer en propriété de classe.

export class LoginComponent implements OnInit {

  constructor(private authService: AuthService) {  // On a ajouté `private`
    // `authService` contient une instance de AuthService
  }

  ngOnInit() {
    // `this.authService` contient aussi une instance AuthService 
    // `this.authService` est utilisable partout dans la classe
  }

}

Remarques :

  • On peut injecter autant de services qu’on souhaite dans le même constructeur :
constructor(private authService: AuthService, private dataService: DataService...)
  • L’injection de dépendance fonctionne dans le constructeur de n’importe quelle classe Angular, c’est à dire toute classe avec un décorateur Angular (@Component, @Injectable, @Directive, @Pipe, @NgModule…).

Utiliser un service venant d’Angular (ou d’une librairie) avec l’injection de dépendace