Lorsqu’un enfant souhaite transmettre une information à son parent, il peut le faire en exploitant l'event binding. Pour cela, 2 étapes sont nécessaires :
dans le TypeScript de l’enfant, créer un output emitter ainsi qu’une méthode qui lui permettra d’émettre une valeur;
dans le template HTML du parent, par event binding dans la balise de l’enfant, récupérer cette valeur.
Pour créer un OutputEmitter, il suffit d’utiliser l’expression output(), comme on l’aurait fait avec un input. L’output ainsi créé possède une méthode emit() qui lui permet de transmettre l’information désirée (cf. la méthode buttonClicked() ci-dessous).
import {Component, input, output} from '@angular/core';
import {Course} from '../services/mon-service.service';
import {FormsModule} from '@angular/forms';
@Component({
selector: 'app-cours',
imports: [
FormsModule
],
templateUrl: './cours.component.html',
styleUrl: './cours.component.scss'
})
export class CoursComponent {
// on crée ici un attribut dont on indique que la valeur sera un nombre
// et sera optionnellement transmise par le parent
index = input(0); // équivalent à input<number>(0);
// si on veut obliger le parent à transmettre une valeur, on utilise
// input.required à la place de input
module = input.required<Course>();
// le nombre qui va se trouver dans l'input
mynumber = 0;
// pour transmettre des informations vers le parent, on crée un événement,
// qua j'ai appelé, ici, myevent. Dans le parent, on n'aura plus qu'à
// utiliser l'event binding (myevent)="méthode(...)". Le <number> indique
// que l'information sera un nombre.
myevent = output<number>();
buttonClicked() {
// On émet l'événement myevent. Le parent pourra récupérer la valeur
// transmise (this.mynumber)
this.myevent.emit(this.mynumber);
}
}
Pour tester l’émission de l’événement, j’ai rajouté ci-dessous au template HTML du CoursComponent un input associé à l’attribut this.mynumber et un bouton qui permet de déclencher l’émission de l’événement :
<ul>
<li>élément {{index()}} : {{module().nom}} : {{module().nb_etuds}} étuds</li>
</ul>
<input [(ngModel)]="mynumber" />
<button (click)="buttonClicked()">transmettre au parent</button>
On a terminé l’étape 1. Passons à la deuxième, celle où le parent récupère l’événement. Pour cela, dans son template HTML, par event binding, il capture l’événement. Celui-ci a précisément le nom de l’attribut qu’on avait créé avec output().
<input [(ngModel)]="idMonComp" placeholder="saisir un id"/>
<button (click)="rediriger()">Rediriger vers</button>
@for (module of UE; track module.nom) {
<app-cours [index]="$index" [module]="module"
(myevent)="childAfficher($event)" />
}
Notez le $event, c’est un mot-clef qui permet de récupérer la valeur transmise par l’événement. Ici, pour l’afficher, on va simplement utiliser la console, c’est ce que fait la méthode childAfficher() :
import {Component, OnInit, signal} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {Course, MonServiceService} from '../services/mon-service.service';
import {Router} from '@angular/router';
import {CoursComponent} from '../cours/cours.component';
@Component({
selector: 'app-courses',
imports: [
FormsModule,
CoursComponent
],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent implements OnInit {
titre = signal('composant courses');
UE : Course[] = [];
idMonComp !: string;
constructor(private service : MonServiceService,
private router : Router) {}
ngOnInit() {
this.service.getCourses().subscribe(result => {
this.UE = result;
});
}
rediriger() {
if (typeof this.idMonComp === 'undefined') this.idMonComp = '0';
this.router.navigateByUrl(`/mon-comp/${this.idMonComp}`);
}
childAfficher(nombre: number) {
console.log(`l'input de l'enfant contient ${nombre}`);
}
}
Si on utilise les codes ci-dessus, que l’on saisit « 12345 » dans l’input en dessous du 1er « élément » et que l’on clique sur le bouton à sa droite, on verra apparaître le message souligné en rouge dans la console :
Vers le haut de la page des topics se trouve un bouton « nouveau sujet ». Quand on clique dessus, on souhaite que cela ouvre une fenêtre permettant de saisir ce nouveau sujet. Pour cela, créez un nouveau composant create-topic-dialog et ajoutez dedans le bouton « nouveau sujet ». Pour l’instant, le bouton ne fait rien.
Ajoutez une instance du composant CreateDialogComponent dans le fichier
topics.component.html
.
Quand on clique sur le bouton, on souhaite maintenant qu’un popup s’ouvre, nous demandant de saisir le sujet. Il s’agit d’une fenêtre modale :
Règle
Dans le domaine des weberies, on parle de fenêtres de dialogue et de fenêtres modales. Dans les deux cas, l’idée est de faire apparaître par dessus la page web courante une fenêtre qui permet de saisir ou d’afficher des informations. La différence entre une fenêtre modale et une non modale, c’est que la première ne permet plus d’interagir avec la page web tant qu’elle n’est pas fermée tandis que la seconde permet toujours d’interagir avec la page web. Une fenêtre de dialogue peut être modale, on parle alors simplement de fenêtre modale, ou non modale et on la qualifie alors juste de fenêtre de dialogue.
Regardez l’url ci-dessous, qui vous montre comment créer aisément la fenêtre de dialogue. Pour ouvrir une fenêtre modale, il faut simplement remplacer show() par showModal() :
https://blog.angulartraining.com/how-to-create-a-simple-modal-dialog-with-angular-277ea7f96da1
Maintenant, faites en sorte que le bouton « Nouveau sujet » ouvre la fenêtre modale et que celle-ci contienne un bouton permettant de la fermer.
Dans votre backend, écrivez un script PHP saveNewTopic.php
dont le $_POST
est censé contenir une chaîne de caractères non vide (le nouveau sujet) ainsi que
l’identifiant du cours auquel ce sujet devrait appartenir. Pour l’instant, le
script se contente de renvoyer un message d’erreur contenant cet identifiant
ainsi que le sujet.
Dans le forum de démonstration, la fenêtre modale est la suivante :
Faites en sorte que la vôtre ait un aspect similaire. Notamment, vous voyez qu’il
y a deux boutons : « Fermer » qui ferme la fenêtre sans essayer de créer le sujet et
« Créer le sujet », qui essaye de le créer. Pour ce dernier, pour l’instant, associez
l’événement (click) à l’appel d’une méthode createTopic() qui requête votre
script saveNewTopic.php
.
Si le backend renvoie une erreur, le message d’erreur correspondant
apparaît dans la fenêtre modale, sinon aucun message n’apparaît.
Une fois que votre méthode createTopic() fonctionne correctement, rajouter un id="…" dans la balise dialog du fichier create-topic-dialog.component.html, où … a la même valeur que le #…. Par exemple :
<dialog #myDialog id="myDialog">
Pour fermer la fenêtre modale à partir du TypeScript, il suffit alors d’exécuter le code suivant :
const dialog = document.querySelector<HTMLDialogElement>("#myDialog");
if (dialog) dialog.close();
Modifiez donc votre composant de manière à ce que, lorsque l’on n’a pas reçu de
message d’erreur, la fenêtre modale se ferme (modifiez votre script saveNewTopic.php
pour qu’il renvoie un message sans erreur pour tester).
Après que la fenêtre modale a été fermée, rouvrez la. Vous verrez que l’input contient encore le sujet qui avait été tapé précédemment, voire également le message d’erreur s’il y en avait un. Ce n’est pas souhaitable, il faudrait réinitialiser le contenu de la fenêtre à chaque fois qu’on l’ouvre. Pour cela, vous pouvez exploiter le fait qu’il est possible de relier l’événement (click) à l’exécution de plusieurs expressions :
(click)="méthode1();méthode2()"
Dans le composant create-topic-dialog, créez une interface NewTopic :
export interface NewTopic {
idTopic: number;
sujet: string;
}
Faites en sorte que, lorsque l’on a réussi à saisir un nouveau sujet, on transmette au composant TopicsComponent le nouveau sujet au format NewTopic. Puis faites en sorte que le TopicsComponent affiche ce nouveau sujet : pour cela, il suffit de rajouter le nouveau sujet au tableau de sujets stocké dans le composant TopicsComponent.
Dans votre backend, modifiez le script PHP saveNewTopic.php
afin qu’il permette
d’ajouter réellement les nouveaux sujets. Pour cela, le script doit vérifier :
que le sujet transmis dans le $_POST est non vide,
que l’utilisateur suit bien le cours,
que le cours ne possède pas déjà ce sujet.
Si au moins une des trois conditions ci-dessus n’est pas vérifiée, le script renvoie un message d’erreur. En revanche, si toutes les conditions sont réunies, le sujet est créé dans la base de données et les propriétés du cours sont mises à jour dans la base (nombre de topics). Enfin, le script renvoie un message contenant l’identifiant du nouveau sujet.
Testez votre script avec Postman.