AngularAtlaséd. 22.2

Chap. 02Fondamentaux modernes06 / 75

Data binding et événements

Interpolation, bindings de propriétés et d’attributs, événements avec $event et filtres de touches, et comment [( )] est construit — ce qui entre dans le DOM et ce qui en revient.

Un template n’est pas du HTML statique : Angular le garde relié à la classe du composant. Les crochets et parenthèses indiquent le sens des données — {{ }} et [ ] portent des valeurs de la classe vers le DOM, ( ) ramène des événements dans la classe, et [( )] fait les deux.

La plupart des bugs de débutant ici ne sont pas des erreurs de syntaxe. Ils viennent de trois questions : dans quel sens vont les données, est-ce que je modifie une propriété du DOM ou un attribut HTML, et quel élément a vraiment reçu le clic ?

Pourquoi c’est important
Chaque écran que vous construisez est fait de ces quatre bindings. Quand vous savez exactement ce que chacun écrit et à quel moment, un champ qui ne se réinitialise pas, un bouton qui reste désactivé ou un clic qui ouvre autre chose ne sont plus des mystères.

Quatre bindings, deux sens

Les données descendent avec {{ }} et [ ], les événements remontent avec ( ). Angular réévalue les expressions de droite quand les signals qu’elles lisent changent, et n’écrit dans le DOM que si le résultat diffère de ce qu’il a écrit la dernière fois.

SyntaxeSensCe qui se passe
{{ expr }}classe → DOMdéfinit le texte d’un nœud (toujours du texte, jamais du HTML)
[prop]="expr"classe → DOMdéfinit une propriété de l’élément DOM
[attr.x]="expr"classe → DOMajoute ou retire un attribut HTML
(event)="stmt"DOM → classeexécute une instruction quand l’événement survient
[(x)]="sig"dans les deux sensun property binding et un événement de changement, en un seul
<!-- classe → DOM -->
<h2>{{ title() }}</h2>                          <!-- interpolation : du texte -->
<img [src]="avatarUrl()" [alt]="userName()" />  <!-- property binding -->
<td [attr.colspan]="wide() ? 2 : null"></td>    <!-- attribute binding -->

<!-- DOM → classe -->
<button (click)="save()">Enregistrer</button>   <!-- event binding -->

<!-- dans les deux sens -->
<app-rating [(value)]="stars" />                <!-- two-way binding -->

L’interpolation : toujours du texte

{{ }} transforme la valeur en chaîne et la place dans un nœud texte. Le HTML contenu dans la valeur s’affiche tel quel, il n’est pas interprété — c’est ce qui vous protège des XSS. On lit un signal en l’appelant : {{ count() }}. Gardez l’expression légère et sans effet de bord : elle peut s’exécuter à chaque passage de la détection de changements.

<!-- la valeur devient du texte : '<b>Ana</b>' s’affiche avec ses chevrons, pas en gras -->
<p>Bonjour, {{ userName() }}!</p>

<!-- n’importe quelle expression sans effet de bord ; on appelle les signals -->
<p>{{ items().length }} articles · {{ total() | currency: 'EUR' }}</p>
<p>{{ user()?.address?.city ?? 'pas encore de ville' }}</p>

<!-- ✗ le texte de la fonction du signal, pas sa valeur -->
<p>{{ count }}</p>

Le property binding définit une propriété du DOM

[value]="name()" ne touche pas au HTML. Il définit la propriété value de l’élément input. Les attributs sont les valeurs de départ écrites dans le HTML ; les propriétés sont l’état vivant de l’élément. Quand l’utilisateur tape, la propriété change et l’attribut reste tel quel. Et Angular n’écrit la propriété que lorsque name() change — si la classe contient toujours la même valeur, une réinitialisation ne change pas ce que l’utilisateur a tapé.

@Component({
  selector: 'app-profile',
  template: `
    <!-- définit input.value ; ne change pas l’attribut value="" -->
    <input [value]="name()" (input)="name.set(box.value)" #box />
    <button [disabled]="saving()" (click)="save()">Enregistrer</button>
    <button (click)="reset()">Réinitialiser</button>
  `,
})
export class Profile {
  readonly name = signal('Ana');
  readonly saving = signal(false);

  reset() {
    // ne marche que parce que (input) garde name() à jour ;
    // avec [value] seul, name() vaut toujours 'Ana' et set('Ana') ne change rien
    this.name.set('Ana');
  }
}
LivePropriété ou attribut, et une réinitialisation qui ne réinitialise rien
name()dans la classe'Ana'
input.valuepropriété DOM'Ana'
getAttribute('value')attribut HTMLnull

synchroniséLe champ et le signal disent tous deux 'Ana'.

Attribut statique ou property binding
clics : 0

Le premier bouton est désactivé : l’attribut existe, et sa valeur texte ne compte pas.

En mode [value] : tapez un nom de famille après « Ana », puis appuyez sur name.set('Ana'). Recommencez dans le second mode et comparez le tableau et les deux boutons en dessous.

Dans le premier mode, le champ affiche un texte dont la classe ne sait rien. name.set('Ana') donne au signal la valeur qu’il avait déjà : rien ne change, et Angular n’écrit pas dans l’input. Relire l’input avec (input) — ou lier dans les deux sens avec [( )] ou un formulaire — garde la classe et le DOM au même pas. Remarquez que getAttribute('value') reste null du début à la fin : Angular n’a jamais défini l’attribut.

Quand il n’y a pas de propriété : [attr.]

Certains attributs n’ont pas de propriété correspondante : aria-*, colspan, data-*, les attributs SVG. Pour eux, utilisez [attr.nom]. Une valeur null ou undefined retire l’attribut — c’est ainsi qu’on active et désactive aria-current. Les classes et les styles ont leurs propres bindings, présentés dans [class] et [style].

Les attributs booléens sont le piège classique : le navigateur regarde seulement si l’attribut existe. disabled="false" est une chaîne, l’attribut est présent, et le bouton est désactivé. [disabled]="false" donne à la propriété le booléen false.

<!-- pas de propriété DOM pour ceux-là : on lie l’attribut -->
<td [attr.colspan]="span()">…</td>
<svg><circle [attr.r]="radius()" /></svg>
<div [attr.data-state]="state()"></div>

<!-- null retire l’attribut : aria-current n’existe que sur le lien actif -->
<a [attr.aria-current]="active() ? 'page' : null" href="/orders">Commandes</a>

<!-- ✗ l’attribut existe, donc le bouton est désactivé -->
<button disabled="false">Enregistrer</button>
<!-- ✓ la propriété reçoit le booléen false -->
<button [disabled]="false">Enregistrer</button>

L’event binding : ( )

(click)="save()" ajoute un listener sur l’élément et exécute l’instruction quand l’événement survient. $event est l’objet de l’événement DOM : un MouseEvent pour un clic, un KeyboardEvent pour une touche, ou la valeur émise par l’output() d’un composant. Pour lire un champ, une référence de template comme #box est plus simple et entièrement typée : (input)="name.set(box.value)".

<button (click)="save()">Enregistrer</button>

<!-- $event est l’événement DOM ; pour un output(), c’est la valeur émise -->
<div (pointermove)="track($event.clientX, $event.clientY)"></div>
<app-rating (valueChange)="stars.set($event)" />

<!-- une référence de template est typée HTMLInputElement : pas de cast -->
<input #box (input)="query.set(box.value)" />

<!-- ✗ en mode strict : 'value' does not exist on type 'EventTarget' -->
<input (input)="query.set($event.target.value)" />

Les événements remontent (bubbling)

Un clic part de l’élément le plus profond puis remonte par chaque ancêtre, en exécutant aussi leurs handlers (click). C’est ainsi qu’un bouton Supprimer placé dans une ligne cliquable ouvre aussi la ligne — le handler de la ligne s’exécute juste après celui du bouton.

LiveUn bouton Supprimer dans une ligne cliquable
  • Commande n°1042
  • Commande n°1043
  • Commande n°1044
Handlers exécutés, dans l’ordre

Aucun clic pour l’instant.

Appuyez sur Supprimer pour une commande et regardez Détails et la liste des handlers. Passez ensuite à $event.stopPropagation() et recommencez.

$event.target est l’élément où le clic a commencé, et il est le même dans tous les handlers. $event.currentTarget est l’élément dont le handler s’exécute. stopPropagation() dans le handler intérieur est la solution rapide. Une meilleure structure consiste souvent à ne rien imbriquer : l’action de la ligne devient un vrai lien ou un vrai bouton à côté de Supprimer, pas un handler de clic sur toute la ligne — et les utilisateurs du clavier peuvent alors l’ouvrir aussi.

<ul>
  @for (order of orders(); track order.id) {
    <!-- la ligne ouvre la commande… -->
    <li (click)="open(order)">
      Commande n°{{ order.id }}
      <!-- …et sans stopPropagation(), un clic ici atteint aussi la ligne -->
      <button (click)="remove(order); $event.stopPropagation()">Supprimer</button>
    </li>
  }
</ul>

<!-- souvent mieux : deux actions séparées, sans imbrication, accessibles au clavier -->
<li>
  <a [routerLink]="['/orders', order.id]">Commande n°{{ order.id }}</a>
  <button (click)="remove(order)">Supprimer</button>
</li>

Filtres de touches et action par défaut du navigateur

Angular permet de filtrer les événements clavier directement dans le binding : (keydown.enter), (keydown.escape), (keydown.shift.enter), (keydown.control.s). Les modificateurs doivent correspondre exactement : (keydown.enter) ne se déclenche pas pour Maj+Entrée. Votre handler s’exécute avant l’action par défaut du navigateur — insérer un saut de ligne, envoyer le formulaire, suivre un lien — et $event.preventDefault() annule cette action.

<textarea
  #msg
  [value]="draft()"
  (input)="draft.set(msg.value)"
  (keydown.enter)="send($event)"
  (keydown.escape)="draft.set('')"
></textarea>
<!-- (keydown.enter) ne se déclenche pas pour Maj+Entrée : le navigateur ajoute une ligne, comme d’habitude -->
LiveUne zone de chat : Entrée envoie, Maj+Entrée ajoute une ligne
  • Aucun message pour l’instant.
(keydown)—
(keydown.enter)—
(keydown.shift.enter)—
(keydown.escape)—

Appuyez sur une touche dans la zone de message.

Écrivez un message et appuyez sur Entrée dans chaque mode. Essayez ensuite Maj+Entrée et Échap, et regardez quels bindings s’exécutent.

Sans preventDefault(), le navigateur insère le saut de ligne après que votre handler a vidé draft, et l’événement (input) réécrit le texte. Un détail de plus que la plupart des zones de chat ratent : pendant qu’on tape du japonais ou du chinois avec une méthode de saisie (IME), Entrée valide les caractères. Vérifiez $event.isComposing et ignorez la touche dans ce cas.

[( )], c’est [ ] plus ( )

La « banane dans la boîte » est un raccourci. [(value)]="name" signifie un property binding sur value plus un listener pour l’événement valueChange qui réécrit la valeur. Si vous passez un WritableSignal, Angular met le signal à jour pour vous. Dans vos propres composants, model() crée les deux moitiés ; pour les champs de formulaire, utilisez Signal Forms.

<!-- le raccourci… -->
<app-rating [(value)]="stars" />

<!-- …signifie exactement ceci -->
<app-rating [value]="stars()" (valueChange)="stars.set($event)" />

<!-- avec un WritableSignal, Angular appelle set() pour vous ;
     l’enfant le déclare avec : value = model(0) -->

Les variables de référence de template

#nom sur un élément vous donne cet élément dans le reste du template ; sur un composant, l’instance du composant. C’est le moyen le plus rapide de lire un champ ou d’appeler focus() sans passer par $event.target, dont le type n’est que EventTarget. Dans la classe, la même référence s’obtient avec viewChild().

<!-- sur un élément : l’élément lui-même -->
<input #search placeholder="Rechercher" />
<button (click)="search.focus()">Focus</button>

<!-- sur un composant : l’instance du composant -->
<app-video-player #player />
<button (click)="player.play()">Lecture</button>

<!-- dans la classe : readonly search = viewChild<ElementRef<HTMLInputElement>>('search') -->

Bonnes habitudes / à éviter

Bonnes habitudes
  • Garder la source de vérité dans la classe (un signal) et relire chaque changement depuis le DOM.
  • Utiliser des références de template (#box) plutôt que $event.target quand il vous faut une valeur.
  • Utiliser [attr.] pour aria-* et data-*, et null pour retirer un attribut.
À éviter
  • Appeler des fonctions coûteuses dans {{ }} ou [ ] — elles se réexécutent à chaque passage.
  • Les attributs booléens statiques avec une valeur (disabled="false") : seule la présence de l’attribut compte.
  • stopPropagation() par habitude : l’événement disparaît aussi pour l’analytics, pour les menus qui se ferment au clic à l’extérieur, et pour vos collègues.

Pièges fréquents

  • Une réinitialisation qui ne réinitialise rien. Le champ était lié dans un seul sens, l’utilisateur a tapé, et la classe garde l’ancienne valeur. La redéfinir ne change rien.
  • Oublier les parenthèses. {{ count }} affiche la fonction du signal, pas sa valeur. Le compilateur vous prévient ; n’ignorez pas l’avertissement.
  • La ligne s’ouvre quand on clique sur Supprimer. Le clic est remonté du bouton à la ligne. Arrêtez-le, ou n’imbriquez pas les actions.
  • Un saut de ligne reste après l’envoi. L’action par défaut d’Entrée s’est exécutée après le handler. Appelez $event.preventDefault().
  • Écrire $event.target.value. target est un EventTarget, donc cela ne compile pas en mode strict. Utilisez une référence de template, ou lisez la valeur dans la classe avec un cast.

Aide-mémoire

{{ expr }}             du texte dans le DOM ; le HTML est échappé ; on appelle les signals : {{ count() }}
[prop]="expr"          une propriété DOM (value, disabled, src, checked) ou un input de composant
[attr.x]="expr"        un attribut HTML (aria-*, data-*, colspan, svg) ; null le retire
[class.x] / [style.x]  une classe ou un style ; voir la page [class] et [style]
(event)="stmt"         un listener ; $event = l’événement DOM ou la valeur émise
(keydown.enter)        filtres de touches ; les modificateurs doivent correspondre : shift.enter, control.s, escape
[(x)]="sig"            [x]="sig()" + (xChange)="sig.set($event)"
#ref                   l’élément, ou l’instance du composant, dans le template

quand Angular écrit    seulement si la valeur diffère de la dernière écrite
attribut ou propriété  attribut = valeur de départ dans le HTML ; propriété = état vivant
bubbling               un clic exécute les handlers de chaque ancêtre ; target reste le même
actions par défaut     s’exécutent après votre handler ; $event.preventDefault() les annule

Chap. 02 · 0 sur 8 terminées

Leçon terminée ?

Marquez-la : elle apparaîtra sur votre carte, dans le sommaire et sur la page d’accueil.

Se marque toute seule une fois la leçon lue en entier.

  1. Standalone et bootstrap
  2. Data binding et événements
  3. Control Flow : @if, @for, @switch
  4. @let et les nouvelles expressions de template
  5. @defer — Lazy Loading dans les templates
  6. Bindings de classe et de style
  7. Styles des composants et encapsulation
  8. Pipes : quand et comment
Voir toute votre carte

Les 75 pages · tapez pour filtrer

  • 01Nouveautés d’Angular 21 & 22Tous les changements importants de la v21 et de la v22, en bref, avec un lien vers la page qui explique chacun.Départ
  • 01Votre première application, pas à pasUne liste de lecture construite d’un composant vide jusqu’à une application terminée — signals, @for, inputs et outputs, un service et un formulaire, pas à pas.Départ
  • 01Décisions rapides« Où mettre ça ? », « Signal ou Observable ? », « Shared ou feature ? » — des réponses courtes aux questions de tous les jours.Départ
  • 01Questions d’entretien Angular60 vraies questions d’entretien pour profils junior, confirmé et senior, avec la réponse à donner, la relance et les signaux d’alerte. Plus un entretien blanc.Départ
  • 02Standalone et bootstrapComment une application démarre sans NgModule : bootstrapApplication, app.config.ts, imports dans le composant.Fondamentaux modernes
  • 02Data binding et événementsInterpolation, bindings de propriétés et d’attributs, événements avec $event et filtres de touches, et comment [( )] est construit — ce qui entre dans le DOM et ce qui en revient.Fondamentaux modernes
  • 02Control Flow : @if, @for, @switchLa syntaxe de blocs qui remplace *ngIf/*ngFor/ngSwitch, avec track, @empty et vérifications d’exhaustivité.Fondamentaux modernes
  • 02@let et les nouvelles expressions de templateVariables locales avec @let, fonctions fléchées, spread, regex, instanceof, commentaires dans les balises.Fondamentaux modernes
  • 02@defer — Lazy Loading dans les templatesChargez les composants lourds uniquement quand c’est nécessaire : triggers, prefetch, placeholder, loading, error.Fondamentaux modernes
  • 02Bindings de classe et de stylePourquoi [class.x] et [style.x] ont remplacé ngClass et ngStyle (avec migration automatique depuis la v21).Fondamentaux modernes
  • 02Styles des composants et encapsulation:host, les trois modes d’encapsulation, les thèmes avec des variables CSS, et pourquoi ::ng-deep est un dernier recours.Fondamentaux modernes
  • 02Pipes : quand et commentPipes pures vs impures, pipes personnalisées, et comment choisir entre une pipe, computed() et une méthode.Fondamentaux modernes
  • 03signal() et computed()Les primitives réactives : état modifiable, état dérivé, égalité, untracked et règles d’immutabilité.Signals et réactivité
  • 03effect() — quand OUI, quand NONEffets de bord synchronisés avec les Signals : localStorage, logs, API impératives. Et leurs pièges.Signals et réactivité
  • 03linkedSignal() — état dérivé modifiableUn signal qui se réinitialise quand sa source change, mais que vous pouvez aussi modifier à la main.Signals et réactivité
  • 03resource, rxResource, httpResourceDes données asynchrones sous forme de Signals : status, value, error, reload, annulation automatique. Stable depuis la v22.Signals et réactivité
  • 03debounced() — signals différésLa version « debounce » d’un signal, sans RxJS. Parfait pour la recherche.Signals et réactivité
  • 03Listes : rechercher, filtrer, trier, paginerUne chaîne de signals computed qui ne recalcule que ce qui a changé, avec les filtres dans l’URL pour qu’un lien rouvre la même vue.Signals et réactivité
  • 03Les Observables depuis zéroCe qu’est un Observable, subscribe et unsubscribe, les opérateurs que vous utilisez chaque semaine, froid ou chaud — et quand un signal suffit.Signals et réactivité
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — et quand RxJS reste le bon choix.Signals et réactivité
  • 04input() et output()Les inputs comme Signals (required, transform, alias) et les outputs typés. Les données descendent, les événements remontent.Composants : communication
  • 04model() — binding bidirectionnelLe « banana-in-a-box » [( )] avec une seule API. Quand l’utiliser, et quand input + output est préférable.Composants : communication
  • 04viewChild et contentChildLes queries comme Signals : viewChild, viewChildren, contentChild, contentChildren, l’option read.Composants : communication
  • 04Lifecycle et DestroyRefQuels hooks comptent encore à l’ère des Signals, afterNextRender, DestroyRef et ngOnChanges typé.Composants : communication
  • 04Projection de contenung-content avec select, plusieurs slots, contenu par défaut et le piège de la projection conditionnelle.Composants : communication
  • 04ng-template et ngTemplateOutletLes templates comme valeurs : les render props en Angular, contexte typé et personnalisation des composants.Composants : communication
  • 05Smart vs DumbContainer vs présentation : qui détient l’état, qui se contente d’afficher, et comment bien les séparer.Conception des composants
  • 05Composants génériques <T>Un DataTable<T> ou un Select<T> correctement typé, avec des templates pour les cellules.Conception des composants
  • 05Composants dynamiquesNgComponentOutlet, createComponent avec inputBinding/outputBinding, et un tableau de bord construit à partir d’une configuration.Conception des composants
  • 05Directives et composition d’hôteLes directives d’attribut, les métadonnées host: {} et la Directive Composition API (hostDirectives).Conception des composants
  • 05Contrôles de formulaire personnalisésFormValueControl (Signal Forms) vs ControlValueAccessor : une notation par étoiles, dans les deux variantes.Conception des composants
  • 05Change DetectionOnPush est la valeur par défaut depuis la v22, Zone.js a disparu depuis la v21. Ce qui déclenche le rendu et comment éviter les mauvaises surprises.Conception des composants
  • 06inject() et @Service()Le nouveau décorateur @Service() de la v22, inject() vs le constructeur, et le contexte d’injection.Dependency Injection
  • 06Providers et hiérarchie des injecteursRoot vs route vs composant, useClass/useValue/useFactory/useExisting, et les modificateurs optional/self/skipSelf.Dependency Injection
  • 06InjectionToken et provideX()Configuration typée, fonctions provideFeature(), makeEnvironmentProviders et initializers.Dependency Injection
  • 06injectAsync() — services en Lazy LoadingChargez un service lourd uniquement quand vous en avez besoin, avec prefetch à l’idle.Dependency Injection
  • 07Structure des dossierscore / shared / features, ce que contient chacun, et à quoi ressemble l’intérieur d’une feature.Architecture d’application
  • 07Shared vs featureQuand déplacer un composant dans shared et (surtout) quand NE PAS le faire. Une checklist concrète.Architecture d’application
  • 07Interfaces et modèlesInterface en ligne ou fichier séparé ? DTO vs modèle de domaine, type vs interface, où les ranger.Architecture d’application
  • 07State Management avec les SignalsStores simples à base de Signals, facades, état local vs global, et quand NgRx devient nécessaire.Architecture d’application
  • 07Guide de style et nommageLes conventions officielles actuelles : noms de fichiers sans suffixes, protected, readonly, ordre des membres.Architecture d’application
  • 07Barrels, alias et frontièresindex.ts, alias de chemins, API publique d’une feature et règles de dépendances vérifiables automatiquement.Architecture d’application
  • 07Erreurs : @boundary et ErrorHandlerLe nouveau bloc @boundary de la v22.2, l’ErrorHandler global, les erreurs HTTP et les erreurs de resource.Architecture d’application
  • 08Routing moderne et Lazy LoadingloadComponent, routes enfants, paramètres comme inputs et héritage des paramètres (le nouveau comportement par défaut de la v22).Routing
  • 08Guards et resolverscanActivate, canMatch, canDeactivate et resolve sous forme de fonctions, avec redirections via UrlTree / RedirectCommand.Routing
  • 09Signal Forms — les basesDes formulaires bâtis sur les Signals : form(), [formField], validation par schéma. Stable depuis la v22.Formulaires
  • 09Signal Forms — avancéValidation personnalisée et inter-champs, async/HTTP avec debounce, listes dynamiques, désactivé/masqué, schémas réutilisables.Formulaires
  • 09Reactive Forms typésFormGroup typé, nonNullable, FormArray — et leur cohabitation avec les Signal Forms.Formulaires
  • 10HttpClient, interceptors et couche d’APIHttpClient sans configuration (v21), Fetch par défaut (v22), interceptors fonctionnels et une couche d’API avec mapping des DTO.HTTP et données
  • 11Performance — une checklistCe qui compte vraiment : OnPush + Signals, track, @defer, routes en Lazy Loading, images, bundles et Hydration.Qualité et performance
  • 11Tests avec VitestVitest est le runner par défaut depuis la v21. TestBed, composants avec Signals, services, HTTP et harnesses.Qualité et performance
  • 11DevTools : regarder dans votre applicationChrome DevTools et Angular DevTools pas à pas : ce que montre chaque panneau, avec des exercices qui fonctionnent sur ce site.Qualité et performance
  • 11Angular AriaDes composants headless et accessibles que vous stylez comme vous voulez : tabs, accordion, menu, listbox...Qualité et performance
  • 12SSR, Prerendering et modes de renduQuand rendre sur le serveur, quand au build et quand uniquement dans le navigateur : RenderMode par route, app.routes.server.ts et les coûts réels.SSR et Hydration
  • 12Hydration : event replay et incrémentaleComment le navigateur reprend le HTML du serveur sans le re-rendre : Hydration complète, event replay, @defer (hydrate on …) et erreurs de mismatch.SSR et Hydration
  • 12Code compatible serveurwindow n’existe pas sur le serveur : PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, le cache HTTP et PendingTasks.SSR et Hydration
  • 13Micro frontendsQuand découper une application en plusieurs déploiements vaut le coup, et quand c’est juste de la complexité : Native Federation, Module Federation, iframes, Web Components.Architecture à grande échelle
  • 13Web Components avec Angular ElementscreateCustomElement : un composant Angular utilisé comme balise HTML n’importe où, plus la communication entre applications via des événements et BroadcastChannel.Architecture à grande échelle
  • 13Monorepo, bibliothèques et frontièresUn workspace avec plusieurs applications et bibliothèques : ng generate library, Nx, points d’entrée secondaires, publication et règles de dépendances.Architecture à grande échelle
  • 13Architecture hexagonale (ports et adapters)Un domaine sans Angular, des ports sous forme de classes abstraites et des adapters interchangeables : HTTP, localStorage ou en mémoire, sans toucher à l’UI.Architecture à grande échelle
  • 14Les Signals sous le capotLe graphe réactif : producteurs et consommateurs, push-pull, pourquoi computed est lazy et sans glitch, le problème du diamant et quand les effects s’exécutent.Réactivité avancée
  • 14RxJS avancé : opérateurs d’ordre supérieurswitchMap, mergeMap, concatMap et exhaustMap sur un diagramme interactif, plus retry avec backoff, shareReplay et comment éviter les fuites.Réactivité avancée
  • 14NgRx SignalStoreState Management à grande échelle sur les Signals : withState, withComputed, withMethods, rxMethod, entités et hooks — et quand un store simple suffit.Réactivité avancée
  • 14Machines à états avec les signalsFini les états impossibles : une machine typée sur des signals, avec transitions, gardes et un diagramme d’états en direct.Réactivité avancée
  • 15WebSockets : un temps réel qui résiste au réseauUn socket typé sous forme de signals : reconnexion avec backoff et jitter, heartbeat, file d’attente hors ligne et sécurité SSR.Temps réel et hors ligne
  • 15Mises à jour optimistes et rollbackUne UI instantanée qui reste honnête : snapshot et rollback, réponses dans le désordre, clés d’idempotence.Temps réel et hors ligne
  • 15Offline-first : Service Worker et cacheLe Service Worker d’Angular : stratégies de cache, annonce des nouvelles versions et file d’attente pour les modifications faites hors ligne.Temps réel et hors ligne
  • 16Web WorkersDes calculs lourds sans bloquer l’UI : un vrai worker dans la page, l’échange de messages et quand ça n’en vaut pas la peine.UI avancée et performance
  • 16Listes géantes : virtual scroll100 000 lignes sans latence : le virtual scroll du CDK, itemSize, trackBy et les alternatives (pagination, scroll infini).UI avancée et performance
  • 16Animations modernes et View Transitionsanimate.enter et animate.leave à la place de @angular/animations (déprécié), transitions CSS et View Transitions à la navigation.UI avancée et performance
  • 16Fuites mémoire : les trouver et les corrigerAbonnements, timers et listeners qui survivent à leur composant — comment les repérer dans les DevTools et les fermer.UI avancée et performance
  • 17Sécurité : XSS, sanitisation et CSPCe qu’Angular fait automatiquement contre le XSS, quand bypassSecurityTrust devient dangereux, plus la CSP avec nonce, Trusted Types et XSRF.Sécurité et internationalisation
  • 17Authentification : tokens et refreshUn interceptor qui ajoute le token, le renouvelle une seule fois sur une 401 et rejoue les requêtes en attente — plus où conserver le token.Sécurité et internationalisation
  • 17OAuth 2.1 et OpenID Connect avec PKCELe flux authorization code avec PKCE, pas à pas : verifier et challenge, state et nonce, l’ID token, et pourquoi un BFF est plus sûr.Sécurité et internationalisation
  • 17Internationalisation (i18n)$localize, l’attribut i18n, ICU plural/select, un build par langue vs des traductions à l’exécution, et le formatage selon la locale.Sécurité et internationalisation