Angular - output() vs EventEmitter: Lequel choisir en 2026?

Xavier Moreau .

1 mars 2026

Code sur un écran d'ordinateur portable, affichant du code HTML et JavaScript, avec des éléments de développement web, comme un `EventEmitter` dans Angular.

Dans Angular, faire remonter une information d’un composant enfant vers son parent est une opération banale en apparence, mais elle conditionne souvent la clarté de toute l’architecture frontend. Le duo output() et EventEmitter sert précisément à ça, avec une version moderne de l’API qui mérite d’être comprise avant d’être appliquée partout. Ici, je vais montrer comment cela fonctionne, quand l’utiliser, quand préférer une autre approche, et quels pièges évitent de transformer un simple événement en code difficile à maintenir.

Ce qu’il faut garder en tête avant de brancher un enfant sur son parent

  • output() est l’API recommandée pour les nouveaux composants Angular.
  • @Output() + EventEmitter reste pleinement supporté dans les bases existantes.
  • Un output ne remonte pas dans le DOM : le parent doit l’écouter explicitement.
  • L’événement peut transporter une valeur simple ou un objet plus riche via $event.
  • Si tu synchronises une valeur plutôt qu’un événement ponctuel, model() peut être plus adapté.

Pourquoi cette communication existe

Le problème à résoudre est simple : l’enfant sait qu’un fait s’est produit, mais il ne doit pas connaître les détails du parent qui va l’exploiter. Je préfère penser à ce mécanisme comme à un contrat d’émission clair : l’enfant annonce un événement, le parent décide quoi en faire. C’est beaucoup plus propre que de laisser un composant enfant appeler directement une méthode du parent ou manipuler un état partagé sans cadrage.

Dans Angular, cette logique complète bien le flux classique des inputs : les données descendent vers l’enfant, les événements remontent vers le parent. La documentation Angular rappelle aussi que ces événements personnalisés ne remontent pas dans le DOM, donc il ne faut pas compter sur une propagation implicite comme avec certains événements natifs. Une fois ce cadre posé, l’implémentation devient beaucoup plus lisible, et on peut passer à la mécanique concrète.

Comment ça circule entre un composant enfant et son parent

La version moderne consiste à déclarer une sortie avec output(), puis à appeler emit() quand quelque chose mérite d’être signalé. Le parent, lui, écoute cette sortie avec la syntaxe de liaison d’événement dans le template. Angular transforme alors cet échange en contrat typé, ce qui aide énormément dès qu’on commence à transmettre autre chose qu’un simple booléen.

import { Component, output } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
    
  `,
})
export class ChildComponent {
  saved = output<{ id: number; label: string }>();

  save() {
    this.saved.emit({ id: 7, label: 'Brouillon' });
  }
}
@Component({
  selector: 'app-parent',
  template: `
    
  `,
})
export class ParentComponent {
  onSaved(payload: { id: number; label: string }) {
    console.log(payload);
  }
}

Ce qui compte ici, ce n’est pas seulement la syntaxe. C’est le fait que le composant enfant reste autonome, tandis que le parent conserve la responsabilité du traitement. Angular indique aussi que le nom d’un output est sensible à la casse, et qu’un output peut être renommé via un alias si c’est utile pour éviter un conflit avec un événement natif. Pour une création dynamique de composant, on peut même s’abonner au résultat de façon programmatique, ce qui reste pratique dans des cas plus avancés. Avec cette base, la vraie question devient maintenant : faut-il écrire ce lien avec output() ou avec l’ancien couple @Output() et EventEmitter ?

output() ou @Output() + EventEmitter

La documentation Angular actuelle recommande output() pour les nouveaux projets, et ce choix n’est pas cosmétique. L’API est plus directe, plus cohérente avec l’écosystème moderne d’Angular, et elle évite un peu de bruit autour de la déclaration des sorties. En face, @Output() + EventEmitter reste totalement supporté, donc il n’y a aucune urgence à réécrire tout un codebase stable juste pour suivre une mode.

Approche Ce que j’en pense Quand l’utiliser Point de vigilance
output() Plus moderne, plus lisible, et mieux alignée avec Angular récent. Nouveaux composants, refactor ciblé, codebase que tu veux garder nette. Doit être appelé dans un initialiseur de propriété, pas ailleurs.
@Output() + EventEmitter Parfaitement valide, surtout dans un projet déjà structuré autour de cette syntaxe. Migration progressive, maintenance, coexistence avec du code existant. EventEmitter s’appuie sur RxJS Subject, donc il ne faut pas le traiter comme un simple bus global.

Je résume souvent ce choix de façon très concrète : si tu écris du neuf, pars sur output(). Si tu maintiens de l’existant, garde @Output() quand il est déjà partout, puis migre progressivement si cela a un vrai intérêt. Cette logique évite les réécritures décoratives et garde le projet cohérent. Reste maintenant à voir dans quels cas un simple output suffit, et quand une liaison plus forte avec model() est plus pertinente.

Quand un output suffit et quand model() est plus juste

Un output est très bien quand l’enfant signale un événement ponctuel : un clic, une suppression, une validation, une fermeture de panneau, une sélection de ligne. Dans ces cas-là, je veux que le parent soit informé, pas que l’enfant devienne responsable de l’état global. C’est la bonne frontière entre notification et synchronisation.

En revanche, si tu construis un composant dont la valeur doit rester synchronisée entre parent et enfant, Angular propose aujourd’hui model() pour les scénarios de liaison bidirectionnelle. La documentation officielle montre ce pattern pour les composants de type compteur, où l’enfant expose une valeur et le parent la lie avec la syntaxe [(...)]. Je considère cela comme un meilleur choix qu’un empilement d’outputs artificiels quand on veut simplement maintenir une valeur partagée proprement.

  • Output simple : fermeture de modal, clic sur bouton, suppression d’un élément.
  • Output enrichi : envoi d’un objet avec identifiant, libellé et métadonnées.
  • model() : champ de formulaire, compteur, valeur que le parent et l’enfant doivent garder synchronisée.

Cette distinction compte beaucoup dans les interfaces complexes, car elle évite les composants qui mélangent événement, état et logique métier dans le même flux. Et une fois cette frontière claire, il reste à sécuriser l’implémentation contre les erreurs les plus fréquentes.

Les pièges qui cassent souvent l’échange

Le premier piège que je vois souvent, c’est l’usage de output() hors d’un initialiseur de propriété. Angular le refuse, et ce n’est pas une coquetterie de syntaxe : le compilateur doit pouvoir reconnaître les sorties au moment de l’analyse statique. Le second piège, c’est d’attendre un comportement de propagation du DOM. Un output n’est pas un événement HTML standard, donc il doit être capté directement par le composant parent.

Il y a aussi quelques erreurs plus discrètes mais tout aussi pénibles :

  • Nommer une sortie comme un événement natif et créer une ambiguïté inutile.
  • Oublier que les noms sont sensible à la casse.
  • Envoyer un payload trop gros alors que le parent n’a besoin que d’un identifiant.
  • Utiliser EventEmitter comme si c’était une source d’état partagée, alors que ce n’est pas son rôle.
  • Changer le nom dans le template avec un alias sans mettre à jour la lecture du code TypeScript.

Je rappelle aussi un détail utile pour les architectures par héritage : les outputs peuvent être hérités par une classe enfant, ce qui est pratique dans les composants de base réutilisés. Quand on garde ces contraintes en tête, le mécanisme devient très fiable au lieu de se transformer en source de bugs intermittents. Il ne reste plus qu’à aligner tout cela avec une manière de coder qui garde les composants simples à faire évoluer.

Ce que je retiens pour écrire des composants plus nets

Si je devais résumer la pratique en une règle simple, je dirais ceci : un output sert à signaler une action, pas à cacher de la logique métier. Plus le payload est petit et explicite, plus le composant reste facile à tester et à faire évoluer. Plus le nom de l’événement décrit l’action réelle, plus le code du parent se lit vite.

Dans un projet Angular moderne, je pars donc généralement sur output(), j’utilise @Output() + EventEmitter quand je maintiens du code déjà structuré comme ça, et je réserve model() aux cas où la valeur doit être synchronisée dans les deux sens. Si je dois migrer une base ancienne, je le fais par zones cohérentes plutôt qu’en big bang, ce qui limite les régressions et laisse le code plus homogène après coup. C’est la voie la plus simple pour garder des composants frontend lisibles, testables et franchement plus agréables à maintenir.

Questions fréquentes

`output()` est la nouvelle API recommandée pour les projets Angular modernes, offrant une syntaxe plus concise et typée. `@Output() + EventEmitter` reste entièrement supporté et est idéal pour maintenir la compatibilité avec les bases de code existantes ou lors de migrations progressives.
Utilisez `output()` pour tout nouveau composant ou lors d'un refactoring ciblé pour aligner votre code avec les pratiques Angular les plus récentes. C'est plus lisible et mieux intégré à l'écosystème moderne d'Angular. Pour l'existant, `@Output()` est parfait.
Non, un `output()` Angular ne propage pas d'événements dans le DOM. Le composant parent doit explicitement écouter cet événement via la liaison d'événement dans son template. C'est un mécanisme de communication direct entre parent et enfant, non une propagation DOM.
`model()` est idéal lorsque vous avez besoin d'une liaison bidirectionnelle, c'est-à-dire quand la valeur d'un composant enfant doit rester synchronisée avec celle de son parent. Un `output()` est parfait pour signaler un événement ponctuel, tandis que `model()` gère la synchronisation continue d'une valeur.
Évitez d'appeler `output()` en dehors d'un initialiseur de propriété. Ne confondez pas la propagation d'un `output` avec celle des événements DOM. Soyez attentif à la casse des noms, à ne pas surcharger le payload et à ne pas utiliser `EventEmitter` comme un bus d'état global partagé.

Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

angular output eventemitter communication enfant parent angular output angular
Autor Xavier Moreau
Xavier Moreau
Je m'appelle Xavier Moreau et je cumule 14 ans d'expérience dans le développement web, avec un accent particulier sur JavaScript, le backend, le NoSQL et la sécurité. Mon intérêt pour ces domaines a émergé dès mes débuts dans la programmation, où j'ai découvert la puissance des technologies web et leur capacité à transformer des idées en réalité. J'aime expliquer des concepts complexes de manière accessible, en aidant les lecteurs à naviguer dans les défis techniques qu'ils rencontrent. Au fil des ans, j'ai développé une expertise solide en vérifiant mes sources, en comparant les informations et en simplifiant des sujets parfois ardus. Je m'efforce toujours de fournir des contenus utiles, précis et à jour, en suivant les tendances du secteur et en organisant mes connaissances de manière claire. Mon objectif est d'accompagner les passionnés et les professionnels du développement web dans leur quête de compréhension et d'innovation.

Commentaires (0)

Ajouter un commentaire