Services

Un service est simplement une classe où la logique de l’application est factorisée. Si plusieurs composants veulent pouvoir accéder aux mêmes données, effectuer le même type de calculs, se connecter à une base de données, etc, alors plutôt que de dupliquer du code, on utilise un service.

Un composant n’a pas à s’occuper d’instancier les services qu’il veut utiliser, ils sont injectés par le module: le composant reçoit directement une instance de classe en paramètre.

Créer un service


Utiliser un service


HTTP et Observable

Si on vaut remplacer les données statiques par un appel HTTP

  1. Importer HttpClientModule dans le module

     +import { HttpClientModule } from '@angular/common/http';
    
     @NgModule({
       ...
       imports: [
         BrowserModule,
     +   HttpClientModule
       ]
     })
    
  2. Injecter HttpClient dans le service et utiliser la méthode get pour requêter un fichier distant. Pour caster le résultat, la fonction get prend un type générique en paramètre (spécifié entre chevrons):

     import { Injectable } from '@angular/core';
     import { HttpClient } from '@angular/common/http';
    
     interface Employee {
       id: number,
       name: string,
       age: number
     }
    
     @Injectable({
       providedIn: 'root'
     })
     export class DbService {
       constructor(private http: HttpClient) {}
    
       public getEmployees() {
         return this.http.get<Employee[]>("/assets/employees.json");
       }
     }
    
  3. Au niveau du composant, la méthode getEmployees() retourne désormais un objet Observable. Ajouter un listener avec subscribe pour récupérer la liste des employés quand le fichier est reçu.

     ngOnInit() {
       this.dbService.getEmployees().subscribe(data => {
         this.employees = data;
       });
     }
    

Gérer les erreurs


Subject

  1. Créer un service avec une propriété de type Subject
    Le subject est un observer: il permet de diffuser des notifications.

    A partir de cet observer, on crée un obversable: les composants pourrons ainsi ajouter un listener et recevoir les notifications du subject associé.
    Par convention, les propriétés de type Observable sont suffixées d’un dollar.

    interact.service.ts:

     import { Injectable } from '@angular/core';
     import { Subject } from 'rxjs';
    
     @Injectable({
       providedIn: 'root'
     })
     export class InteractService {
       private _source = new Subject<string>();
       public message$ = this._source.asObservable();
    
       sendMessage(value: string) {
         this._source.next(value);
       }
     }
    
  2. Injecter le service dans le composant souhaitant envoyer des notifications et se servir de la méthode sendMessage() qu’on a crée dans le service.

    app.component.ts:

     import { Component } from '@angular/core';
     import { InteractService } from './interact.service';
    
     @Component({
       selector: 'app-root',
       template: `<button (click)="greet()">Send message</button>
                  <app-child></app-child>`
     })
     export class AppComponent {
       constructor(private interactService: InteractService) {}
    
       greet() {
         this.interactService.sendMessage('Hello World');
       }
     }
    
  3. Injecter le service dans les composants souhaitant recevoir des notifications et y ajouter un listener.

    child.component.ts:

     import { Component, OnInit } from '@angular/core';
     import { InteractService } from './interact.service';
    
     @Component({
       selector: 'app-child',
       template: `<p>Child says: {{ message }}</p>`,
     })
     export class ChildComponent implements OnInit {
       message: string;
    
       constructor(private interactService: InteractService) {}
    
       ngOnInit() {
         this.interactService.message$.subscribe(message => {
           this.message = message;
         })
       }
     }