Angular - Paramétrer l'injection de dépendance avec @Injectable

Dans cet article, nous allons découvrir en détail comment utiliser l'injection de dépendances avec le décorateur @Injectable d'Angular. Avant tout, il est nécessaire de connaître les notions des composants angular si ce n'est pas le cas, vous pouvez en apprendre davantage ici !

Définition : L’injection de dépendance

L’injection de dépendance est une notion fondamentale du framework Angular. C’est un design pattern implémenté directement par ce framework. Quand Angular instancie un component, il peut résoudre les dépendances en les injectant via le constructeur du component. Les attributs des classes de notre projet (component, service ou autres) seront instanciés sans notre intervention. Si l’injection a été configurée, le framework choisit quelle instance utiliser. Il peut décider de créer une nouvelle instance de l’objet ou bien d'en choisir une déjà existante (principe singleton). C’est ce que nous allons voir dans cet article.

L’injecteur d’Angular

Angular met à disposition plusieurs injecteurs de dépendance. Comme dit précédemment, leur rôle est d'instancier et de fournir les dépendances demandées par les différentes classes de nos applications. Chaque injecteur dispose d'une portée qui lui est propre. Cette portée peut-être : l’application entière, un module et/ou un composant.

schéma portée injecteur angular @injectable

Le décorateur @Injectable

Décorateur : définition

Avant toute chose, qu’est-ce qu’un décorateur ? Un décorateur est une annotation précédée d’un @. Son rôle est de factoriser certaines instructions en surchargeant le comportement de base (principe de POO), d’ajouter des métadonnées, des propriétés ou des paramètres à nos classes. Angular dispose de plusieurs décorateurs pour différentes fonctions : pour la communication inter-component, la résolution de dépendance et beaucoup d’autres.
Vous pouvez même créer vos propres décorateurs !

Le cas du décorateur @Injectable

Revenons à notre décorateur @Injectable. Il permet de rendre notre classe détectable par l’injecteur, donc si vous injectez une dépendance sans ce décorateur, le framework vous retournera une erreur.

Les différents types d’injecteur

Injecteur : root

a) Syntaxe

Dans le décorateur @Injectable de votre service, dans le paramètre “providedIn” inscrivez ”root” :

1
2
3
4
5
6
7
8
import { Injectable } from '@angular/core';
 
@Injectable({
 providedIn: 'root',
})
export class AnyService {
 constructor() { }
}
b) Cas d’utilisation

Utilisez l’injecteur root lorsque vous souhaitez que les dépendances soient accessibles dans toute l’application. Si dans votre application vous avez besoin d’un service quelconque utilisé dans plusieurs modules, alors il est préférable d’utiliser cette solution.

De plus, il n’y aura qu’une seule instance de ce service (singleton) disponible pour toute l’application. Cela vous évitera une diminution de performance liée à de multiples instanciations inutiles.
c) Exemple

Prenons l’exemple d’une application qui récupère des données via une API. Si ces données sont utilisées dans différents modules, par différents component et par la couche métier, il semble pertinent de rendre disponible l’instance du service à toute l’application.

Injecteur par module

a) Syntaxe

Dans le décorateur @Injectable de votre service, dans le paramètre “providedIn” inscrivez le nom du module dans lequel vous voulez injecter la dépendance :

1
2
3
4
5
6
7
8
9
10
11
12
import { Injectable } from '@angular/core';
import { AnyModule } from './any.module';
import { ANY } from './mock-any';
 
@Injectable({
 // nous déclarons que ce service doit être créé
 // par n'importe quel injecteur qui inclut AnyModule.
 providedIn: AnyModule,
})
export class AnyService {
 getAny() { return ANY; }
}
b) Cas d'utilisation

Utilisez l’injecteur par module si les dépendances ne doivent être accessibles qu’à certains modules. Les instances seront disponibles uniquement dans les modules déclarés dans l’annotation @injectable. Là aussi, les dépendances seront des singletons (instanciés une seule fois).

c) Exemple

Prenons l’exemple d’une application utilisant un système d’authentification. On trouve dans cette application un module appelé AuthenticationModule. Dédié à la gestion d’authentification. Ce module dispose de plusieurs composants qui ont besoin d’un service d’authentification. Dans ce cas-là, on veut que l’AuthenticationService ne soit accessible que dans ce module afin de restreindre son utilisation aux components dédiés. On décide alors d’injecter le service via l’injecteur du module AuthenticationModule.

Injecteur par component

a) Syntaxe

Dans le décorateur du component, dans le paramètre “providers” placez entre crochets la liste des dépendances à injecter :

1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from '@angular/core';
import { AnyService } from './any.service';
 
@Component({
 selector: 'app-any',
 providers: [ AnyService ],
 template: `
   ‹h2›My title‹/h2›
   ‹app-any-list›‹/app-any-list›
 `
})
export class AnyComponent { }
b) Cas d'utilisation

Si vous souhaitez que la dépendance ne soit accessible que dans un seul composant et dans ses composants enfants.

Attention, dans ce cas-ci le component possédera sa propre instance de la dépendance. La dépendance n’est donc plus instanciée comme un singleton ce qui pourrait avoir des répercussions au niveau des performances de votre application.
c) Exemple

Par exemple, un composant d'édition d’utilisateur UserEditorComponent qui a besoin d’un service de mise en cache, doit posséder sa propre instance de UserCacheService. On utilisera donc l’injecteur par component pour ce cas-là.

Conclusion

Désormais vous savez où et comment injecter des services avec Angular. Si vous avez des questions n'hésitez pas à me les poser en commentaire !

Si vous n’êtes pas encore à l’aise avec les notions de services, vous pouvez vous rendre sur cet article : Les services

Sources