Angular propose de nombreuses méthodes pour échanger les données au sein de l’application. À l’intérieur d’un même composant, il y a 4 techniques principales :
L’interpolation prend des valeurs TypeScript (de la classe du composant ou toute expression TypeScript) pour les afficher dans la partie HTML. Elle s’utilise via la syntaxe {{expression}} dans le HTML :
<p>interpolation : {{titre}} et {{3 + 4}}</p>
import { Component } from '@angular/core';
@Component({
selector: 'app-courses',
imports: [],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
titre = 'liste de cours';
}
Si le template HTML du composant app est :
<h1>Ceci est mon composant App</h1>
<app-courses />
<app-courses />
<router-outlet />
on obtient l’affichage suivant :
Notez que rien n’empêche de placer entre les doubles accolades des appels de méthode :
<p>interpolation : {{get_titre()}} et {{3 + 4}}</p>
import {Component} from '@angular/core';
@Component({
selector: 'app-courses',
imports: [],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
titre = 'liste de cours';
get_titre(): string {
return this.titre + ' (dans methode)'
}
}
Le code précédent est utilisable mais pas optimal en termes de performances car il n’aide pas Angular à détecter quand l’affichage doit être modifié (par exemple parce qu’on a changé le titre). Les signaux permettent d’avertir Angular de cela. Leur utilisation est très simple. Au lieu de définir directement titre = valeur;, on écrit titre = signal(valeur); et on importe signal du core d’Angular :
import {Component, signal} from '@angular/core';
@Component({
selector: 'app-courses',
imports: [],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
titre = signal('liste de cours');
}
Que ce soit dans l’interpolation du template HTML ou dans le TypeScript, on accède à la valeur de la propriété titre via titre() :
<p>interpolation : {{titre()}} et {{3 + 4}}</p>
Les signaux sont des wrappers très « light ». On a donc tout intérêt à les utiliser. On peut modifier leurs valeurs avec deux méthodes set, pour affecter une nouvelle valeur, et update pour mettre à jour la valeur courante :
import {Component, signal} from '@angular/core';
@Component({
selector: 'app-courses',
imports: [],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
titre = signal('liste de cours');
constructor() {
// modifications du titre
this.titre.set("toto");
this.titre.update((val) => {return val.toUpperCase();});
}
}
Notez que, comme le montre le code ci-dessus, un composant peut avoir un constructeur. Celui-ci est unique (pas de polymorphisme).
Règle
Quand les variables, propriétés, attributs de vos classes TypeScript auront des interactions avec le template HTML, utilisez des signaux. Vos applications n’en seront que plus efficaces.
L’objectif du property binding est de transfèrer de l’information du TypeScript vers un attribut, une propriété, d’une balise. On l’utilise en encadrant le nom de la propriété en question avec des []. L’exemple suivant vous montre :
comment contrôler l’affichage de la balise <h1> avec du property binding. Ici, La valeur de la propriété hidden de la balise <h1> correspond toujours à celle de l’attribut hide (hide=false <=> affichage).
comment remplir automatiquement le contenu de la balise <input>. Ici, lors de l’initialisation du composant, la valeur de l’attribut val_input est transmise à la balise <input>. Là encore, si l’on modifie la valeur de val_input, celle de la balise <input> sera mise à jour.
<h1 [hidden]="hide()">Titre caché</h1>
<p>interpolation : {{titre()}}</p>
<input [value]="val_input()">
import {Component, signal} from '@angular/core';
@Component({
selector: 'app-courses',
imports: [],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
titre = signal('liste de cours');
hide = signal(true);
val_input = signal('property binding');
}
Voilà ce que produit le code ci-dessus :
L’event binding réalise des transferts dans l’autre sens. Pour l’utiliser, la syntaxe est (nom_événement)="callback()". Lorsque l’événement arrive, on va appeler la méthode callback(). On peut aussi passer un paramètre à cette méthode. Dans ce cas, le paramètre s’appelle $event :
<h1 [hidden]="hide()">Titre caché</h1>
<p>interpolation : {{titre()}}</p>
<input [value]="val_input()" (keyup)="changeTitre($event)">
<button (click)="changeH1()">Hide ou pas le h1</button>
import {Component, signal} from '@angular/core';
@Component({
selector: 'app-courses',
imports: [],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
titre = signal('liste de cours');
hide = signal(true);
val_input = signal('property binding')
changeH1() : void {
this.hide.update((val) => {return !val; });
}
changeTitre(event : KeyboardEvent) {
this.titre.set(`touche : ${event.key}`)
}
}
Ici, chaque fois que l’on clique sur le bouton, la méthode changeH1() de la classe CoursesComponent est appelée et elle change la valeur de hide, ce qui alterne la visibilité de la balise <h1>. Lorsque l’on est en train d’éditer l’input, chaque fois que l’on relâche une touche, la chaîne affichée par interpolation est mise à jour et affiche la touche en question.
Le two-way binding est un mix entre le property binding [] et l’event binding (), d’où la syntaxe [()]. Il permet de transférer des informations dans les deux sens (TypeScript vers HTML et inversement). Pour être précis, la syntaxe est la suivante : [(ngModel)]="nom_attribut". ngModel est un mot-clef d’Angular. nom_attribut est le nom d’un attribut de la classe TypeScript.
la syntaxe ci-dessus est valable même si l’attribut est un signal,
c’est-à-dire qu’ici, il ne faut pas indiquer les () du signal.
Par ailleurs, il faut penser à importer FormsModule (en principe, votre IDE
devrait le faire pour vous).
<p>interpolation : {{val_input()}}</p>
<input [(ngModel)]="val_input">
<button (click)="changeVal()">Change</button>
import {Component, signal} from '@angular/core';
import {FormsModule} from '@angular/forms';
@Component({
selector: 'app-courses',
imports: [
FormsModule
],
templateUrl: './courses.component.html',
styleUrl: './courses.component.scss'
})
export class CoursesComponent {
val_input = signal('property binding');
changeVal() {
this.val_input.set('XXXXX');
}
}
Dans le code ci-dessus, l’input contient un two-way binding, donc toute modification
de val_input dans le TypeScript sera reporté automatiquement vers l’input et
l’interpolation du paragraphe <p></p>. Par exemple,
si on clique sur le bouton Change, cela exécutera la méthode changeVal()
du TypeScript, et l’input et l’interpolation seront mis à jour avec la chaîne « XXXXX ».
À l’inverse, chaque fois que l’utilisateur modifie l’input en tapant du texte dedans,
la valeur de l’attribut val_input du TypeScript est mise à jour, ce qui a pour
conséquence de modifier l’interpolation (cf. le haut de la figure ci-dessous).
Mettez à jour la page de login de votre forum de manière à ce que les données du TypeScript soient synchronisées avec celles du template HTML.
Faites en sorte que le bouton de soumission/d’envoi affiche dans la console Javascript le login et le password saisis par l’utilisateur. Pour afficher la console, cliquez droit dans votre navigateur, ce qui vous permettra d’obtenir le menu déroulant suivant qui, lui-même, vous permettra de sélectionner l’inspecteur :
L’affichage de votre navigateur sera scindé en 2 et vous aurez accès à la console :
Règle
Lorsque vous programmez en Javascript, TypeScript ou Angular, ouvrez systématiquement la console Javascript. Cela vous permettra :
de débugguer en faisant des affichages dans la console;
de voir des erreurs ou warnings qui ne sont pas forcément décelables facilement en regardant la page web affichée.
Dans votre frontend, rajoutez un nouveau composant navbar. Celui-ci contiendra la barre de navigation en haut des pages. Pour la créer, vous pouvez exploiter la classe navbar de la balise <nav> fournie par bootstrap, cf. :
https://getbootstrap.com/docs/5.3/components/navbar
Comme vous pouvez le voir sur le forum de démonstration, la navbar est identique sur toutes les pages du frontend. Pour l’insérer de manière automatique dans toutes les pages, il suffit donc d’inclure ce composant au début du fichier app.component.html. Faites-le et vérifiez que vous voyez bien votre barre de navigation. Supprimez la balise <h1></h1> que vous aviez placée dans ce fichier.