Skip to content

Injection de dépendances

Quel est le but (théorie)

L'injection de dépendances (DI) est un modèle de conception logicielle qui permet de supprimer les dépendances codées en dur dans notre application.

L'injection de dépendances est utilisée pour passer une instance d'une classe à un objet dépendant. Par exemple, si nous avons une variable, par exemple client, dans notre composant, Angular se chargera de fournir un objet client réel au composant.

Angular utilise une classe appelée Injector pour faire du DI. Injector est une instance singleton dont le travail consiste à créer des instances de classes. L'injecteur utilise un ensemble de règles pour répondre à la demande de dépendance.

Créer un service

Avant de parler des injections de dépendances, nous allons créer un service :

ts
export class MyService {
  getTitle() {
    return "Formation Angular"
  }
}
export class MyService {
  getTitle() {
    return "Formation Angular"
  }
}

Oui, un service est tout simplement une classe !

Problèmes :

  1. Comment nous l'avons vu avant, nous pouvons pas utiliser new car si le constructeur change, il faut changer le changer partout.
  2. Nous créons à chaque fois une instance avec new

La solution : L'injection de dépendance (DI).

Injection de dépendance

Voici le côté magique de l'injection de dépendance : nous récupérons l'instance dans le constructeur. Il suffit de créer un paramètre et de mettre le type.

ts
import { Component } from '@angular/core'
import { MyService } from './app.service.ts'

@Component({
  selector: 'app-root',
  template: '<h1>{{ title }}</h1>'
})
export class AppComponent {
  title: string = ''

  constructor(private myservice: MyService) {
      this.title = myservice.getTitle()
  }
}
import { Component } from '@angular/core'
import { MyService } from './app.service.ts'

@Component({
  selector: 'app-root',
  template: '<h1>{{ title }}</h1>'
})
export class AppComponent {
  title: string = ''

  constructor(private myservice: MyService) {
      this.title = myservice.getTitle()
  }
}

Et en privilégiant le hook ngOnInit avec l'injection raccourci de TypeScript :

ts
import {Component, OnInit} from '@angular/core';
import {MyService} from './app.service.ts';

@Component({
  selector: 'app',
  template: '<h1>{{title}}</h1>'
})
export class AppComponent implements OnInit {
  title: string = ''

  constructor(private myservice: MyService) { }

  ngOnInit() {
    this.title = this.myservice.getTitle();
  }

}
import {Component, OnInit} from '@angular/core';
import {MyService} from './app.service.ts';

@Component({
  selector: 'app',
  template: '<h1>{{title}}</h1>'
})
export class AppComponent implements OnInit {
  title: string = ''

  constructor(private myservice: MyService) { }

  ngOnInit() {
    this.title = this.myservice.getTitle();
  }

}

Remarque sur private

ts
class AppComponent {
  constructor(private myservice:MyService) {

  }
}
class AppComponent {
  constructor(private myservice:MyService) {

  }
}

Revient à faire :

ts
class AppComponent {
  myservice:MyService

  constructor(myservice:MyService) {
    this.myservice = myservice;
  }
}
class AppComponent {
  myservice:MyService

  constructor(myservice:MyService) {
    this.myservice = myservice;
  }
}

Le provider

Méthode 1: propriété providers

Bien entendu, cela n'est pas suffisant. Ici, nous n'utilisons pas le mot clé new. Normal, puisque nous utilisons le design pattern DI. C'est le provider qui se charge de créer les instances. Il faut donc les déclarer dans le module

ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {MyService} from './app.service.ts';

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [MyService]
})
export class AppModule {

}
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {MyService} from './app.service.ts';

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [MyService]
})
export class AppModule {

}

C'est donc avec la propriété providers que nous déclarons les services à instancier.

Méthode 2: propriété providedIn

Depuis Angular 9, vous pouvez indiquer que le service s'ajoute dans le provider directement dans le décorateur @Injectable()

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

@Injectable({
  providedIn: 'root'
})
export class MyService {
  getTitle() {
    return "Formation Angular"
  }
}
import { Injectable } from '@angular/core'

@Injectable({
  providedIn: 'root'
})
export class MyService {
  getTitle() {
    return "Formation Angular"
  }
}

La chaîne de caractères root indique que la classe est fournie dans le module racine (AppModule donc)