Archives Wild Code School
Angular

11 - ✏️ Les Services 2, le retour !

Quête 10 sur 16

title-book
Introduction

Reactive extensions for JavaScript (RxJS) est une librairie de flux reactifs qui permet de travailler avec des flux de données asynchrones.

La programmation réactive est un paradime de programmation orienté flux de données et propagation des changements. RxJS peut être utilisé aussi bien dans un navigateur que côté serveur (via Node.js).

Avant de démarrer, assure-toi d'avoir terminé les quêtes suivantes👇

Objectifs 🤓

✅ Se faire injecter un service au sein d'un autre service ✅ Utiliser la librairie RxJS, plus spécifiquement les Observables ✅ Récupérer des données depuis un fichier .json

Dans l'épisode précédent...

Tu te souviens de cette histoire d'application permettant aux utilisateurs de commander des cocktails depuis leur chambre ? Et bien le besoin du patron de l'hôtel a évolué : les clients sont de plus en plus demandeurs de nouvelles recettes de cocktails.

Tu dois toujours garder en tête que ton application évoluera forcément.

Le souci, c'est qu'à l'heure actuelle, le catalogue de cocktails est écrit "en dur" au sein de ton application. C'est-à-dire qu'il est physiquement figé au sein de ton code source... Et cela n'arrange pas le patron de l'hôtel de devoir faire appel à toi à chaque fois qu'il faut mettre à jour la carte ! (Même si c'est un business model rentable, quoique très discutable...)

Le nouveau besoin est simple : faire en sorte que l'on puisse mettre à jour un fichier contenant l'ensemble des cocktails de la carte. L'application doit pouvoir lire dans ce fichier et présenter la carte des cocktails à jour à chacun des clients de l'hôtel.

Ok et concrètement ? 🤓

Voici un exemple de service Angular capable d'aller chercher le contenu d'un fichier .json (situé dans assets/data.json).Dans cet exemple, le fichier .json simule la réponse d'une base de données.

1. Le fichier .json :

json
[
    {
        "name": "Sex on the beach",
        "price": 10,
        "img": "relative-path-to-the-picture"
    },
    {
        "name": "Marguarita",
        "price": 13,
        "img": "relative-path-to-the-picture"
    },
    {
        "name": "Martini",
        "price": 8,
        "img": "relative-path-to-the-picture"
    }
]

Ce fichier contient les cocktails dont on a besoin.

2. Le service qui récupère les données du fichier .json :

typescript
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { Cocktail } from './models/cocktail.model';

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

  private http = inject(HttpClient);

  constructor() { }

  getCocktails(): Observable<Cocktail[]> {
    return this.http.get<Cocktail[]>("assets/cocktails.json");
  }
}

Comme tu peux le voir ici, le service fait appel à un autre service nommé HttpClient. Pour que cette fonctionnalité fonctionne correctement, tu dois d'abord inclure provideHttpClient() dans le tableau des providers de l'objet appConfig du fichier app.config.ts :

ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient()],
};
Info

HttpClient dispose de méthodes correspondant aux différents verbes HTTP utilisés pour effectuer des requêtes, à la fois pour charger des données et pour appliquer des mutations sur le serveur. Chaque méthode renvoie un observable RxJS qui, une fois abonné, envoie la requête puis émet les résultats lorsque le serveur répond. Concernant le fonctionnement détaillé du service HttpClient, tu trouveras les détails au sein de la documentation.

Toutefois, retiens bien que le principe est simple :

Le service va envoyer une requête à ton serveur local et celui-ci lui répondra en lui renvoyant le contenu du fichier contenu à l'adresse renseignée (ici, assets/data.json).

Une fois les données réceptionnées, la réponse du serveur est disponible sous la forme d'un objet générique.

La gestion de l’asynchronicité de la réponse (la réponse n'est pas instantanée) est confiée à un objet de type Observable.

Nous ne traitons pas ici le fonctionnement des observables, tu n'en as pas besoin pour l'instant. Retiens seulement que tu peux créer un observable avec http.get("url-où-récupérer-les-données").

Ok, et dans notre code ? 😚

Ça donne ça :

typescript
  getCocktails(): Observable<Cocktail[]> {
    return this.http.get<Cocktail[]>("assets/cocktails.json");
  }

Dans notre cas, nous avons créé une méthode au sein de notre service CocktailService qui retourne le résultat de cet appel http. Par conséquent, si tu appelles cette méthode, elle te renverra un Observable contenant des cocktails, c'est-à-dire un Observable<Cocktail[]>

Info

Dernière étape : récupérer les données transportées au sein de l'Observable.

On se rend dans le composant dans lequel on souhaite afficher les cocktails CocktailListComponent :

typescript
import { Component, inject } from '@angular/core';
import { CocktailService } from '../cocktail.service';
import { Cocktail } from '../models/cocktail.model';

@Component({
  selector: 'app-cocktail-list',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './cocktail-list.component.html',
  styleUrl: ['./cocktail-list.component.scss']
})
export class CocktailListComponent {

  cocktails: Cocktail[] = [];

  private cocktailService = inject(CocktailService);

  ngOnInit(): void {
    this.cocktailService.getCocktails().subscribe(cocktailsFromJsonFile => {
      this.cocktails = cocktailsFromJsonFile;
    });

  }
}

→ On injecte le service comme tu as appris à le faire dans la quête précédente sur les services → Durant l'initialisation de ton composant (ngOnInit), on déclenche la méthode getCocktails() et l'on s'abonne au flux de données de l'observable avec la méthode .subscribe().

Le délai de réception d'une réponse http est très varié ; il peut être court comme long. Ça va dépendre de plusieurs paramètres : la connexion internet de l'utilisateur, la distance au serveur, la puissance du serveur, etc...

❌ Ce qui est sûr, c'est que tu ne peux pas savoir précisément quand la réponse arrivera à jusqu'à ton code.

✅ S'abonner au flux de l'Observable permet de savoir lorsque les données sont (enfin) reçues et d'agir en conséquence.

→ À l'intérieur de la méthode .subscribe(), on attribue la valeur de la propriété cokctails à la valeur transportée par l'Observable, c'est-à-dire les cocktails récupérés depuis le fichier .json.

↗
↗
Le HttpClient

Ici, vous apprendrez à vous servir du service HttpClient, qui vous permet d'aller chercher des données sur un serveur.

angular.dev
↗
La documentation officielle d'Angular

Le site officiel du framework, contient la documentation et d'autres ressources

angular.dev

Challenge 💪

Étendre les fonctionnalités de notre "CocktailService" 🐙

Tu dois créer un service CocktailService permettant de retourner un certain nombre d'objets de type Cocktail. Ces cocktails se doivent d'être inscrits au sein d'un fichier nommé cocktails.json.

Ton service devra donc demander au serveur le contenu de ce fichier et créer les objets de type Cocktail correspondants. Un objet de type Cocktail doit posséder les caractéristiques suivantes:

  • Un champ nom
  • Un champ prix
  • Un champ image

Le service contient une méthode getCocktails() qui retourne un Observable. La liste des cocktails s'affiche dans un composant nommé CocktailListComponent.

Critères de validation ✅

  • Le service contient une méthode getCocktails() retournant un objet de type Observable
  • Le service CocktailService utilise le service HttpClient
  • Le composant doit posséder une propriété nommée cocktails
  • Le service CocktailService est injecté au sein du composant
  • Le composant utilise la méthode getCocktails() du service et récupère les cocktails
  • L'ensemble des cocktails est affiché via la directive ngFor au sein du template associé au composant.
  • Le code de ton composant doit se trouver dans le dossier app/cocktail-list/
  • Le code de ton service doit se trouver dans le dossier app/

Ressources partagées sur cette quête