11 - ✏️ Les Services 2, le retour !
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 :
[
{
"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 :
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 :
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()],
};
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 :
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[]>
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 :
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.
Là, on attaque quelque chose de difficile. Les observables, l'alpha et l'omega de la gestion des flux ( données ) synchrones / asynchrones. Vous pouvez trouver un complément d'informations sur le site de la librairie rxjs (attention les exemples sont en javascript pur, pas en Typescript, il te faudra adapter un peu ton code).
Ici, vous apprendrez à vous servir du service HttpClient, qui vous permet d'aller chercher des données sur un serveur.
Le site officiel du framework, contient la documentation et d'autres ressources
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 typeObservable - Le service
CocktailServiceutilise le serviceHttpClient - Le composant doit posséder une propriété nommée
cocktails - Le service
CocktailServiceest 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
ngForau 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
- Informations complémentaires pour mieux comprendre le fonctionnement de RxJShttps://www.learn-angular.fr/comprendre-rxjs/