Skip to content

Services

Utilisés pour :

  • Fonctionnalités indépendantes d'un composant
  • Fournir des données ou des fonctionnalités à plusieurs composants
  • Séparer des interactions externes (ex. requêtes à une BD)

Les services sont injectés dans les composants et sont enregistrés (registered) auprès de l'application ou d'un composant.

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

@Injectable({
    providedIn: 'root' //dispo partout
})
export class GlobalService{
    getProduits(): Produit[] {
        return ...
    }
}
import { Injectable } from '@angular/core';

@Injectable()
export class LocalService{
    getProduits(): Produit[] {
        return ...
    }
}
@Component({
selector: 'app-composant',
templateUrl: './composant.component.html',
styleUrls: ['./composant.component.css'],
providers: [LocalService] // dispo ici et dans les composants enfants seulement
})
export class ComposantComponent {  

    private globalService = inject(GlobalService)
    private localService = inject(LocalService)
}

Appels HTTP dans un service

On utilisera des appels HTTP dans nos services pour charger des données provenent d'une API. Pour cela il faudra tout d'abord configurer l'application pour utiliser le clien HTTP d'Angular.

  • Localiser le fichier app.config.ts
  • Dans la section providers, ajouter provideHttpClient() à ceux déjà présent
export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
  ]
};
  • On pourra alors injecter HttpClient directement dans les services de l'application.
  • On crée ensuite des méthodes utilisant le client pour faire les appels. Cette méthode retourne un Observable<T>

Exemple

import { HttpClient } from '@angular/common/http';
import {inject, Injectable} from '@angular/core';
import {Film} from '../models/film';
import {Observable} from 'rxjs';

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

  // Injecter le service
  private http: HttpClient = inject(HttpClient);

  // Méthode qui fait l'appel HTTP et retourne un observable
  getAllFilms(): Observable<Film[]> {
    return this.http.get<Film[]>(url);
  }

}

Utilisation dans un composant

  • Injecter le service dans le constructeur du composant
  • Appeler la méthode du service (souvent lors de la création du composant)
  • S'abonner à la réponse
  • Lors de la destruction du composant, se désabonner
import {Component, inject} from '@angular/core';
import { FilmService } from '../../services/film-service';
import {Film} from '../../models/film';
import {map, Subscription, tap} from 'rxjs';
import {CarteFilm} from '../carte-film/carte-film';

@Component({
  selector: 'app-liste-films',
  imports: [
    CarteFilm
  ],
  templateUrl: './liste-films.html',
  styleUrl: './liste-films.css'
})
export class ListeFilms {
  private filmService: FilmService = inject(FilmService);
  films: Film[] = [];

  // Créer un objet Subscription nous permet de se désabonner plus tard.
  private _filmAbonnement!: Subscription;

  ngOnInit() {
    this._filmAbonnement = this.filmService.getAllFilms()      
      .subscribe({
        next: films => this.films = films,
        error: error => console.log(error),
    })
  }

  ngOnDestroy() {
    this._filmAbonnement.unsubscribe();
  }

}

Attention

L'utilisation de ! permet d'indiquer au compilateur de TypeScript que la propriété sera initialisée, même s'il ne le voit pas. À utiliser avec prudence.

Observables

  • Une collection d'items qui évolue au fil du temps
  • Nous devons s'abonner à un observable (subscribe) qui envoie des notifications :
    • next : quand le prochain item est émis
    • error : une erreur s'est produite; les items ne seront plus émis
    • complete: émission terminée
  • La méthode pipe est utilisée pour transformer les données au fur et à mesure qu'elles arrivent
  • Quand on a terminé on se désabonne (unsubscribe) de l'observable (important !)
  • Par convention on ajouter un $ à la fin de la propriété pour désigner les observables

Manipuler les données reçues

  • On utilisera pipe avant subscribe
  • tap: permet de consulter les données sans les modifier
  • map: permet la transformation des items reçus
this._filmAbonnement = this.filmService.getAllFilms()
      .pipe(
        tap(data => console.log(data)),
        map(data => data.filter(f => f.anneeParution > 2000)),
      )
      .subscribe({
        next: films => this.films = films,
        error: error => console.log(error),
    })

Gestion des URL d'une API

Pour gérer facilement l'URL de l'API, on peut utiliser les fichiers d'environnement. Cela permet également de gérer facilement la différence entre les propriétés de développement et de déploiement.

  • Générer les fichiers d'environnement à l'aide de ng generate environments.
  • Ceci génère les fichiers environment.ts et environment.development.ts situé dans src/environments.
  • Configurer chaque fichier pour indiquer si c'est l'environnement de production et l'url de l'API.
export const environment = {
  production: true,
  apiUrl: 'http://my-prod-url'
};
  • Notez qu'il est également possible de mettre d'autres propriétés et de les utiliser, par exemple si vous avez une adresse d'api différente pour l'authentification.

  • Pour utiliser dans le code, on importera le fichier environment.ts et on utilisera les variables.

  • On utilise ce fichier même durant le développement car lors de la génération des fichiers d'environnement, Angular a également créé une configuration de remplacement de fichiers pour utiliser le bon fichier d'environnement selon qu'on déploie la version de développement ou production.
// Extrait du fichier angular.json
"configurations": {
    "development": {
      "fileReplacements": [
          {
            "replace": "src/environments/environment.ts",
            "with": "src/environments/environment.development.ts"
          }
        ],
        

Références

Doc Angular sur HttpClient
Pour manipuler les observables
Doc Angular sur les fichiers d'environnement