Délégation d'événement en JavaScript : un seul écouteur pour toute une liste

La délégation pose un écouteur sur un ancêtre commun et retrouve l'élément visé avec closest : moins de mémoire, et le contenu ajouté après coup est couvert.
3 min de lecture
Believemy logo

Un tableau de deux cents lignes, un bouton de suppression sur chacune. Poser deux cents écouteurs fonctionne, mais coûte de la mémoire, et ne couvre pas la ligne ajoutée trois secondes plus tard.

Il existe une solution qui tient en un seul écouteur, et elle repose entièrement sur la remontée des événements.


Définition

La délégation d'événement consiste à écouter un ancêtre commun plutôt que chaque élément, puis à identifier au moment du déclenchement l'élément réellement visé. Elle est possible parce qu'un événement remonte de sa cible jusqu'à la racine du document.

JAVASCRIPT
const tableau = document.querySelector("#commandes");

tableau.addEventListener("click", (event) => {
  const bouton = event.target.closest(".supprimer");
  if (!bouton) return;

  const ligne = bouton.closest("tr");
  ligne.remove();
});

Un seul écouteur, quel que soit le nombre de lignes. Les lignes insérées plus tard sont couvertes sans le moindre code supplémentaire, puisque rien n'est branché sur elles.


closest, la pièce maîtresse

event.target désigne l'élément le plus profond touché par le geste, souvent une icône ou un texte à l'intérieur du bouton. Comparer directement ce nœud au sélecteur attendu échoue donc une fois sur deux.

closest remonte depuis un élément vers ses ancêtres et rend le premier qui correspond au sélecteur, l'élément de départ compris. Il rend null quand aucun ancêtre ne correspond, ce qui sert de filtre naturel.

JAVASCRIPT
// <button class="supprimer"><span class="icone"></span> Supprimer</button>

tableau.addEventListener("click", (event) => {
  console.log(event.target.tagName);                    // "SPAN" parfois
  console.log(event.target.closest(".supprimer"));      // toujours le bouton
});


Ce qu'elle apporte

  • Le contenu dynamique fonctionne sans réenregistrement après chaque ajout de ligne.
  • La mémoire ne grandit plus avec le nombre d'éléments affichés.
  • Le nettoyage se réduit à un écouteur unique à retirer quand la vue disparaît.

L'attribut data-*, lu par dataset, complète l'ensemble : il transporte sur chaque ligne l'identifiant à envoyer au serveur, que l'écouteur récupère au moment du clic.


Ses limites

La technique ne s'applique qu'aux événements qui remontent. focus et blur restent sur leur cible : leurs jumeaux focusin et focusout, eux, remontent et se délèguent normalement.

Bon à savoir

Écoutez le conteneur le plus proche, pas document. Un écouteur global voit passer tous les clics de la page, et un appel à stopPropagation placé plus bas suffit à le rendre muet sans explication.


Questions fréquentes

Question

Faut-il déléguer systématiquement ?

Non. Pour un bouton unique, un écouteur direct est plus court et plus lisible. La délégation prend l'avantage sur une collection d'éléments similaires, ou dès que le contenu change au fil de l'usage.


Question

Comment gérer plusieurs actions dans le même conteneur ?

Un seul écouteur suffit encore. Testez les cibles possibles l'une après l'autre avec closest, ou lisez un attribut data-action puis orientez le traitement avec un switch. Cette seconde forme reste lisible même avec une dizaine d'actions.


Question

Le clavier est-il couvert ?

Il l'est si le HTML est correct. Un vrai <button> déclenche un événement click à la touche Entrée comme à la barre d'espace, et cet événement remonte. Un <div> rendu cliquable, lui, n'offre rien de tel et exclut une partie des visiteurs.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.