Comprendre les Inputs et Outputs de composant

Les Inputs et Outputs permettent à deux composants parent-enfant de communiquer entre eux. Quelle est leur syntaxe et quand faut-il les utiliser ?

Introduction

Les Inputs et les Outputs sont une manière pour un composant de communiquer avec son parent à travers une API claire :

  • Les Inputs permettent à un composant de recevoir des données de son parent.
  • Les Outputs permettent à un composant de transmettre un événement ou des données à son parent.

Les Inputs/Outputs sont donc une manière de rendre un composant plus générique et plus réutilisable, puisqu’il peut recevoir des données de l’extérieur (Inputs) et renvoyer des données (Outputs). Pour faire une analogie, on pourrait dire que :

  • Les Inputs sont un peu comme les arguments qu’on passe à une fonction.
  • Les Outputs sont un peu comme la valeur de retour de cette fonction.

Input : Recevoir des données du composant parent

Supposons qu’on crée un composant MeteoComponent qui affiche la météo d’une ville précise. Sans input, il est compliqué d’indiquer la ville dont on veut la météo quand on utilise le composant…

<!-- Météo de quelle ville ? Paris ? Lyon ? Lille ?... -->
<meteo></meteo>

Peut-être que ce composant ne peut afficher que la météo d’une ville précise. Peut-être qu’il injecte un service pour déterminer la ville à utiliser…

En revanche, si le composant accepte un input ville, on peut facilement lui passer une ville en paramètre à chaque fois qu’on l’affiche :

<!-- Template du parent -->
<meteo ville="Paris"></meteo>
<meteo ville="Lyon"></meteo>
<meteo ville="Lille"></meteo>
...

Pour que MeteoComponent accepte un input ville, il suffit de créer une propriété ville dans la classe du composant et de la décorer avec le décorateur @Input() :

import {Component, Input} from "@angular/core";

@Component({
  selector: 'meteo',
  templateUrl: './meteo.component.html'
})
export class MeteoComponent {
  @Input() ville: string;  // <!-- Voici l'input
}

Un input permet donc de rendre un composant plus générique en lui passant à l’utilisation les données dont il a besoin pour s’afficher.

Un composant peut avoir autant d’inputs que vous le souhaitez.

Les inputs supportent également d’autres syntaxes (avec crochets, par exemple) et des usages plus avancés. Voir #39 Inputs de composant Angular.

Output : Transmettre des données au composant parent

Un output permet à un composant de transmettre un évenement / des données à son parent.

Reprenons notre MeteoComponent. Supposons qu’on veuille alerter le composant parent quand MeteoComponent détecte que la température est trop élevée. Pour cela, le composant météo va émettre un événement custom appelé alerteCanicule.

Avec la syntaxe du binding d’événement, le parent peut écouter l’événement alerteCanicule et y réagir en appelant sa méthode boireBeaucoup().

<!-- Template du parent -->
<meteo (alerteCanicule)="boireBeaucoup()"></meteo>

Un événement custom de composant s’appelle un output. Il s’implémente en créant une propriété alerteCanicule dans le composant, décorée avec le décorateur @Output().

import {Component, EventEmitter, Output} from "@angular/core";

@Component({
  selector: 'meteo',
  templateUrl: './meteo.component.html'
})
export class MeteoComponent {
  @Output() alerteCanicule = new EventEmitter<any>();  // <!-- Voici l'output
  
  // Méthode appelée si la température est trop élevée
  onTemperatureRises() {
    this.alerteCanicule.emit();  // Déclenche l'output
  }
}

Notez qu’un output doit contenir une instance de EventEmitter et qu’il faut appeler la méthode emit() de l’output pour déclencher l’événement au moment qui vous paraît opportun.

Dans notre exemple, le composant enfant émet l’événement sans transmettre de données. Le composant parent sait donc que l’événement s’est produit, mais il n’a pas plus d’informations. Dans certains scénarios, il peut être utile de transmettre des données de l’enfant au parent. Voyons comment modifier notre code pour cela.

L’enfant doit passer les données à transmettre à la méthode emit().

export class MeteoComponent {
  temperature = 40;
  
  @Output() alerteCanicule = new EventEmitter<number>();  // Notez le type `number`
  
  onTemperatureRises() {
    this.alerteCanicule.emit(this.temperature);  // Déclenche l'output en passant la température
  }
}

Ici, la température est transmise dans l’output alerteCanicule. Notez qu’on a aussi changé le type de EventEmitter en number pour refléter le type des données transmises.

Côté parent, il faut récupérer les données transmises grâce à la variable système $event :

<!-- Template du parent -->
<meteo (alerteCanicule)="boireBeaucoup($event)"></meteo>

La méthode boireBeaucoup() du parent recevra un paramètre qui contiendra ce que l’enfant a passé à emit(), autrement dit la température dans cet exemple.

Un output permet donc de rendre un composant plus générique en délégant à son parent la responsabilité de gérer les actions. L’enfant se contente d’informer son parent que tel ou tel événement s’est produit, éventuellement en lui transmettant des données.

Un composant peut avoir autant d’outputs que vous le souhaitez.

Les outputs supportent également des usages plus avancés. Voir #40 Outputs de composants Angular.

Informations

Tags : components

Dernière mise à jour :

Auteur : AngularChef

Qualité : Bonne