Le data binding, c'est le pont entre ta classe TypeScript (le composant) et son HTML (le template). Trois formes à connaître par cœur : afficher une valeur ({{ }}), pousser une donnée dans un élément ([prop]), réagir à une action ((event)). Tu as déjà fait ça en AngularJS — la syntaxe a juste changé.
Un composant a deux faces : une classe (les données, la logique) et un template (le HTML affiché). Le data binding les synchronise automatiquement : quand la donnée change, la vue se met à jour ; quand l'utilisateur agit, la classe est notifiée. Tu n'écris jamais de code qui va « chercher l'élément et changer son texte » à la main.
{{ }} et ng-click d'AngularJS : même idée, syntaxe modernisée. Côté Razor (@Model.Nom), la grosse différence : Razor rend le HTML une fois côté serveur, puis c'est figé. Le binding Angular est vivant — il reste branché et se réévalue dès que la donnée bouge, côté navigateur.
{{ }} — afficher une valeurSens : composant → vue. Tu mets une expression TypeScript entre doubles accolades, là où tu écrirais du texte. Angular l'évalue, la convertit en chaîne et l'injecte.
import { Component } from '@angular/core';
@Component({
selector: 'app-poste',
standalone: true,
template: `
<h3>{{ nom }}</h3> // texte dynamique
<p>Mesure : {{ mesure }} °C</p> // toute expression TS valide
<p>Statut : {{ actif ? 'en service' : 'arrêté' }}</p>
`,
})
export class PosteComponent {
nom = 'Four A12';
mesure = 21.4;
actif = true;
}
Change mesure dans la classe → le <p> se met à jour tout seul. L'expression peut faire un calcul simple ou un ternaire, mais reste une expression : pas de if, pas d'affectation, pas d'effet de bord.
[prop] — définir une propriétéSens : composant → vue, mais vers une propriété d'un élément (ou d'un composant enfant), pas vers du texte. On met le nom de la propriété entre crochets, et la valeur est une expression.
<!-- [disabled] cible la PROPRIÉTÉ DOM du bouton, liée à une expression -->
<button [disabled]="!actif">Lancer la mesure</button>
<!-- valeurs dynamiques : src, alt, value… entre crochets -->
<img [src]="iconeUrl" [alt]="nom">
<!-- attribut SANS propriété DOM (aria, colspan, SVG) : [attr.xxx] -->
<td [attr.colspan]="nbColonnes">{{ nom }}</td>
value="21" est un attribut : la valeur initiale écrite dans le markup. Une fois la page vivante, c'est la propriété DOM de l'élément qui compte. [value]="x" écrit dans la propriété, donc c'est ce que tu veux 99 % du temps. Quand l'attribut n'a pas de propriété DOM correspondante (colspan, aria-label, attributs SVG), Angular ne peut pas le lier directement → on passe par [attr.xxx].
(event) — réagir à une actionSens : vue → composant. Le nom de l'événement entre parenthèses, et à droite l'instruction à exécuter (en général un appel de méthode du composant). L'objet événement natif est disponible via $event.
<!-- (click) : on appelle une méthode du composant quand l'utilisateur clique -->
<button (click)="lancerMesure()">Mesurer</button>
<!-- $event = l'objet événement natif (ici l'event input) -->
<input (input)="onSaisie($event)" placeholder="Seuil °C">
export class PosteComponent {
lancerMesure() {
// la logique vit dans la classe, pas dans le template
}
onSaisie(e: Event) {
const valeur = (e.target as HTMLInputElement).value;
}
}
(click)="lancerMesure()", c'est l'ng-click d'AngularJS — et conceptuellement ton gestionnaire d'événement C# (button.Click += …) ou un handler de delegate. Le template dit « quand ça arrive, appelle ça » ; le quoi reste dans la classe.
| Syntaxe | Sens | Sert à |
|---|---|---|
{{ expr }} | composant → vue | afficher du texte |
[prop]="expr" | composant → vue | définir une propriété / valeur |
(event)="action()" | vue → composant | réagir à une action |
[(ngModel)]="champ" | bidirectionnel | les deux à la fois |
Le dernier, [(ngModel)] — surnommé « banana in a box » [()] — n'est rien de magique : c'est juste un property binding [ ] + un event binding ( ) combinés sur le même champ. On le verra en détail avec les formulaires (item 14). Pour l'instant, sache juste le reconnaître.
{{ }} ou [prop] : l'expression d'un template est réévaluée à chaque cycle de détection de changement (souvent très fréquent). Mets une méthode lourde là-dedans et tu la rejoues des centaines de fois par seconde. Garde les expressions de template pures et bon marché ; précalcule dans la classe (ou via un computed() signal — phase 1). (2) [value] (propriété DOM) ≠ value="…" (attribut initial) : en revue, repère les [attr.x] oubliés sur aria-*/colspan. (3) Dans (click)="…", pas de logique inline : délègue à une méthode nommée, c'est testable et lisible.
actif est faux. Quelle écriture est correcte ?<button (click)="mesurer()">, quel est le sens du binding ?{{ calculLourd() }} dans un template ?{{ }} (composant → vue, du texte), property binding [prop] (composant → vue, une propriété), event binding (event) (vue → composant, une action, avec $event). Le bidirectionnel [(ngModel)] = [ ] + ( ) combinés. Pièges de lead : pas de méthode coûteuse en template (rejouée à chaque change detection), et [attr.x] pour les attributs sans propriété DOM.
Angular — Binding dynamic text, properties and attributes (officiel). Lis-la en entier, c'est court. Pour approfondir un sens précis : Event binding et Two-way binding.
[(ngModel)] cache réellement sous le capot ? Demande-moi, ici, maintenant.