Définition de l'injection de dépendance

Si l'on en croit wikipédia :

L'injection de dépendances (dependency injection en anglais) est un design pattern qui permet d'implémenter le principe de l'inversion de contrôle.

Il consiste à créer dynamiquement (injecter) les dépendances entre les différents objets en s'appuyant sur une description (fichier de configuration ou métadonnées) ou de manière programmatique. Ainsi les dépendances entre composants logiciels ne sont plus exprimées dans le code de manière statique mais déterminées dynamiquement à l'exécution.

Toujours selon wikipédia :

L'inversion de contrôle est illustré par le principe de Hollywood : « Ne nous appelez pas, c'est nous qui vous appellerons ». Selon ce principe, l'inversion de contrôle a lieu entre le framework (ou la couche logicielle sous-jacente) et l'application. Ce n'est plus l'application qui gère les appels au framework, mais ce dernier à l'application.

En résumé, lorsque l'on a besoin de faire appel à un service dans Angular (pour récupérer des données distantes par exemple), ce n'est pas au composant de créer une instance du service mais c'est Angular (en temps que framework) qui crée l'instance et la fournit aux composants qui en ont besoin.

L'intérêt d'un tel pattern :

  • Augmentation la réutilisabilité du code
  • Réduction du couplage de classe,  ce qui réduit l'impact des changements dans une classe sur les autres classes.
  • Amélioration des tests d'application
  • Amélioration de la maintenabilité du code
  • Paramétrage centralisé

Serviced Angular et services custom

Concrètement, il existe deux 2 types de services :

  • les services directement fournis pas Angular comme le service HTTP
  • les services custom créés par les développeurs

Utilisation d'un service prédéfini Angular

C'est très simple, il suffit de "l'injecter" dans le constructeur de votre component. Prenons l'exemple du service HTTP et admettons que vous en ayez besoin dans votre component "AppComponent".

import { HttpClient } from '@angular/common/http';
import ...

@Component({
  selector: 'pr-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  courses;
  constructor(private http: HttpClient) {
  }

  ngOnInit() {
    this.http.get('api/courses')
      .suscribe(
        courses => this.courses = courses;
      }
  }
}

Vous constatez que le simple fait de déclarer le paramètre http avec pour type HttpClient vous permet d'utiliser ensuite à votre guise ce service.

Création d'un service custom "Table"

Pour créer un service custom, vous pouvez vous aider de cli-Angular :

ng generate service Table

Ce qui donnera après l'ajout de l'import de l'interface et le renvoie des données :

import { Injectable } from '@angular/core';
import { CardModel } from './models/card.model';

@Injectable({
  providedIn: 'root'
})
export class TableService {

  constructor() { }
  list(): Array<CardModel> {
    return [
      {
        id: 1,
        question: 'Inventeur du web ?',
        anwer: "Tim Berners-Lee'
      },
      {
        id: 2,
        question: 'Inventeur du js ?',
        anwer: "Brendan Eich'
      }
    ]
  }
}

C'est le décorateur "@Injectable" qui permet ensuite d'injecter votre service où bon vous semble comme s'il s'agissait d'un service prédéfini par Angular.

Création d'un service Angular "housing"

ng generate service housing --skip-tests

Cette commande crée le fichier src/app/housing.service.ts

Ajout de données statiques au service

Rendez-vous dans le fichier src/app/home/home.component.ts, et copiez la variable housingLocationList et les valeurs comprises dans le tableau.

Dans le fichier src/app/housing.service.ts :

  • En tout début de fichier importez l'interface :
    import { HousingLocation } from './housinglocation';
  • Dans  la classe HousingService :
    • collez la variable que vous venez de copier depuis HomeComponent juste après la déclaration de la classe.
    • collez les méthodes suivantes, elles permettent aux dépendances d'accéder au service, après le constructeur :
      getAllHousingLocations(): HousingLocation[] {
        return this.housingLocationList;
      }
      
      getHousingLocationById(id: number): HousingLocation | undefined {
        return this.housingLocationList.find(housingLocation => housingLocation.id === id);
      }

Injection de service

En haut du fichier src/app/home/home.component.ts, ajouter "inject" aux items importés depuis @angular/common et importer le service

import { Component, inject } from '@angular/core';
import { HousingService } from '../housing.service';

Toujour dans le fichier src/app/home/home.component.ts remplacer la classe HomeComponent par le code suivant : 

export class HomeComponent {
  housingLocationList: HousingLocation[] = [];
  housingService: HousingService = inject(HousingService);
  
  constructor() {
    this.housingLocationList = this.housingService.getAllHousingLocations();
  }
}

Le constructeur est la première fonction qui s'exécute lors de la création du composant. Le code du constructeur assignera à la propriété housingLocationList la valeur renvoyée par l'appel à getAllHousingLocations().