Dans cette partie je vous présente comment gérer dynamiquement des leçons à partir de fichiers YAML dans une application Angular. Vous apprendrez à récupérer, convertir et stocker des questions, ainsi qu'à intégrer ces fonctionnalités dans votre application.
Récupération et Conversion des fichiers YAML en JSON
Définir l'entité Question
Nous commençons par créer une entité qui définit la structure d'une question :
export class Question {
type: string = "";
titre: string = "";
niveau: string = "";
objectif: string = "";
énoncé: string = "";
ébauches: { [lang: string]: string } = {};
rétroactions: { positive: string, négative: string } = { positive: "", négative: "" };
tests: string = "";
auteur: string = "";
licence: string = "";
}
Création du Service YAML
Générer le service
Exécutez la commande suivante pour créer un service nommé yaml.service
:
ng g service services/yaml
Une fois généré, le fichier yaml.service.ts
ressemble à ceci :
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class YamlService {
constructor() { }
}
Ajouter les fonctions de lecture et de conversion
Installez la bibliothèque js-yaml et ajoutez le code suivant dans votre service :
constructor(private http: HttpClient) { }
readYAML(url: string): Observable<string> {
return this.http.get(url, { responseType: 'text' });
}
convertYAMLToQuestion(yaml: string, url: string): Question {
const includeType = new jsyaml.Type('!include', {
kind: 'scalar',
resolve: (data) => typeof data === 'string',
construct: (data) => {
return url.replace("info.yml", "") + data;
}
});
const CUSTOM_SCHEMA = jsyaml.DEFAULT_SCHEMA.extend([includeType]);
const parsedData = jsyaml.load(yaml, { schema: CUSTOM_SCHEMA });
return parsedData as Question;
}
Ces fonctions permettent de lire un fichier YAML et de le convertir en JSON, en gérant notamment les inclusions pour ajouter le chemin d'accès aux fichiers associés.
Service de Stockage
Générer le service de stockage
Exécutez la commande suivante :
ng g service services/stockage
Nous utiliserons la bibliothèque angular-async-local-storage.
Ajouter les méthodes de stockage
Sauvegarder une question
sauvegarderQuestion(question: Question) {
let dejaPresent = false;
this.storage.get('questions').subscribe((value: unknown) => {
let questions: Question[] = [];
if (value && Array.isArray(value)) {
questions = value as Question[];
}
questions.forEach(val => {
if (val.titre === question.titre) {
dejaPresent = true;
}
});
if (!dejaPresent) {
questions.push(question);
this.storage.set('questions', questions).subscribe(() => {
console.log("Question ajoutée !");
});
}
});
}
Supprimer toutes les questions
toutSupprimer() {
this.storage.clear().subscribe(() => {});
}
Observer les questions sauvegardées
observerQuestions(): Observable<Question[]> {
return this.storage.watch('questions').pipe(
map((value: unknown) => {
return (Array.isArray(value) ? value : []) as Question[];
})
);
}
Ce service permet de sauvegarder, supprimer et observer dynamiquement les questions.
Intégration dans l'Application Angular
Modification de app.component.html
Mettez à jour votre fichier app.component.html
afin d'afficher les leçons et de permettre l'ajout d'un exercice :
<main class="main">
<div class="h-100 w-100 d-flex flex-column gap-3 p-2 overflow-auto">
<app-carte-lecon
*ngFor="let exercice of exercices"
[title]="exercice.titre"
[description]="exercice.objectif"
[niveau]="exercice.niveau">
</app-carte-lecon>
<app-carte-lecon
(ajoutExercise)="chargerExercise()"
[add]="true">
</app-carte-lecon>
</div>
</main>
Modification de app.component.ts
Injectez le StockageService
dans le constructeur et ajoutez la méthode pour charger les questions :
constructor(private gestionStockage: StockageService) { }
ngOnInit(): void {
this.chargerExercise();
}
chargerExercise() {
this.gestionStockage.observerQuestions().subscribe((questions: Question[]) => {
this.exercices = questions;
});
}
Cette configuration permet de charger dynamiquement toutes les questions stockées dans votre application.
Mise à jour du Composant carte-lecon
Injection des Services
Dans le composant carte-lecon
, injectez les services de stockage et YAML dans le constructeur :
constructor(
private gestionStockage: StockageService,
private yamlService: YamlService
) { }
Sauvegarde d'une Question
Ajoutez la méthode suivante pour lire le YAML depuis une URL et sauvegarder la question convertie :
sauvegarderQuestion() {
this.yamlService.readYAML(this.url).subscribe(value => {
this.gestionStockage.sauvegarderQuestion(
this.yamlService.convertYAMLToQuestion(value, this.url)
);
});
}
Template HTML du Composant
Modifiez le template HTML pour gérer l'affichage en mode ajout :
<div [style.background]="color" class="card-custom container d-flex justify-content-between w-100 gap-3">
<div *ngIf="add" class="d-flex flex-column align-items-center justify-content-center w-100 gap-3">
<p>Ajouter un exercice</p>
<input [(ngModel)]="url" placeholder="URL de l'exercice" />
<app-bouton
[colorText]="color"
(onClick)="sauvegarderQuestion()"
title="Ajouter">
</app-bouton>
</div>
<div *ngIf="!add" class="row d-flex flex-column h-100 justify-content-between gap-4">
<div class="d-flex flex-column gap-2">
<h4 *ngIf="title.length > 0">
{{ title }}
</h4>
<p *ngIf="description.length > 0" class="description">
{{ description }}
</p>
</div>
<app-bouton
[colorText]="color"
title="Lancer">
</app-bouton>
</div>
<div class="row d-flex flex-column h-100 justify-content-between">
<app-badge *ngIf="niveau.length > 0" [title]="niveau"></app-badge>
</div>
</div>
Ce template permet à l'utilisateur de saisir une URL contenant une question de progression et de l'ajouter à l'application.
Vous disposez désormais d'une application Angular capable d'ajouter dynamiquement des exercices.
On se retrouve semaine prochaine pour un nouveau blog !
Références
-
Repo NODECA js-yaml (Page consulté le 19 février 2025)
-
Repo CYRILLETUZI, angular-async-local-storage (Page consulté le 19 février 2025)
-
Documentation Angular, Angular (Page consulté le 19 février 2025)
Commentaires