[Actualité] Comprendre la délégation d'événement en JavaScript
par
, 28/05/2015 à 17h57 (3215 Affichages)
La délégation d'événement, qu'est-ce que c'est ?
La délégation d'événement est une technique assez courante en JavaScript qui consiste à poser des écouteurs d'événement non pas sur l'élément HTML ciblé, mais sur l'un de ses ancêtres dans le DOM.
Comment ça marche ?
Le concept essentiel pour comprendre cette technique est la notion de bouillonnement d'un événement. À de rares exceptions prêt, quasiment tous les événement bouillonnent.
Si l'on se représente une page Web comme une feuille de papier sur laquelle on poserait d'autres feuilles de tailles différentes et placées à des endroits précis selon l'arborescence des balises et la mise en page CSS, on peut se représenter un événement (un clic sur une balise par exemple) comme étant intercepté par l'élément le plus au-dessus de l'empilement (et inversement, le plus profond dans l'arborescence du DOM). C'est donc cet élément qui va recevoir l'événement. Le bouillonnement est le mécanisme qui va faire « remonter » cet événement jusqu'au plus haut niveau de l'arborescence (la première feuille de papier) en passant par tous les éléments se trouvant à l'emplacement où l'événement a été déclenché, permettant ainsi à tous les gestionnaires d'événements associés de se déclencher.
En résumé, si l'on considère le code HTML suivant
et que vous placez un écouteur d'événement clic sur la div, cliquer sur le texte du span déclenchera l'événement de la div bien que ce span « cache » cette dernière. Ceci est possible grâce au bouillonnement.
Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 <body> <div> <span>Cliquer ici</span> </div> </body>
Pour en revenir à notre délégation d'événement, nous pourrons savoir, avec l'objet Event associé à tout événement, quel élément HTML a réellement déclenché cet événement (Event.target) et si ce dernier est bien celui que nous souhaitons cibler.
À quoi cela peut-il servir ?
Il y a deux cas typiques d'utilisation de la délégation d'événement.
• Lorsque l'on souhaite associer des événements similaires à différents éléments.
Par exemple, imaginons que l'on souhaite afficher un texte initialement masqué en cliquant sur des items d'une liste ordonnée. Plutôt que de définir autant d'événement que d'éléments dans la liste, on pourra n'en utiliser qu'un seul placé sur la balise <ul>
Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 <ul id="maListe"> <li class="element" data-texte="foo">Item 1</li> <li class="element" data-texte="bar">Item 2</li> <li class="element" data-texte="baz">Item 3</li> <li class="element" data-texte="toto">Item 4</li> <li class="element" data-texte="titi">Item 5</li> <li class="element" data-texte="tata">Item 6</li> <li>Item 7</li> <li>Item 8</li> <li>Item 9</li> <li class="element" data-texte="42">Item 10</li> </ul>Voir l'exemple sur JSFiddle.
Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 document.getElementById('maListe').addEventListener('click', function(e){ var initElem = e.target; if(initElem.className != 'element'){ // Si l'élément n'est pas un de ceux à traiter return; } alert(initElem.dataset.texte); });
Dans ce code, on cherche à afficher le contenu de l'attribut data-texte pour tous les élément ayant la classe element.
On commence d'abord par récupérer l'élément ayant reçu l'événement. On vérifie ensuite si cet élément est bien du type que l'on cible, si ce n'est pas le cas, on stoppe l'exécution de la fonction, sinon, on affiche le message.
• Lorsque l'on veut prévoir des gestionnaires d'événements sur des éléments n'étant pas encore présents dans la page.
Il est de plus en plus fréquent, avec les interfaces riches et AJAX, que le contenu d'une page évolue en fonction des actions de l'utilisateur.
On peut donc avoir à gérer des événements sur des éléments qui n'existent pas au chargement de la page mais qui sont susceptibles d'y apparaitre.
Seulement, lorsque l'on déclare un gestionnaire, il ne peut s'appliquer qu'à des éléments effectivement présents au moment de la déclaration de l'écouteur : JavaScript n'est pas devin ni prédictif.
Pour cela, on pourra facilement poser le gestionnaire sur un ancêtre connu (et existant) dans lequel seront insérés les futurs éléments.
Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 <div id="parent"></div> <button>Ajouter un élément</button>Voir l'exemple sur JSFiddle.
Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 document.getElementById('ajout').onclick = function(){ document.getElementById('parent').innerHTML = '<span id="enfant">Elément enfant ajouté dynamiquement</span>'; }; document.getElementById('parent').addEventListener('click', function(e){ var initElem = e.target; if(initElem.id == 'enfant'){ alert('Vous avez cliqué !'); } });
Au moment de déclarer l'événement, l'élément enfant n'existe pas, pourtant, lorsqu'on l'insère dans la page et que l'on clique dessus, le message s'affiche.
Aller plus loin
Il est important, quand on utilise la délégation d'événement, de faire attention que si l'élément ciblé possède des éléments enfants, alors Event.target peut ne pas correspondre à celui ciblé, il faudra dans ce cas remonter l'arborescence jusqu'à l'élément sur lequel le gestionnaire est posé en testant à chaque palier si l'élément en cours est celui recherché.
Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 var initElem = false, tmpElem = e.target; do{ if(tmpElem.id == 'id_recherche'){ initElem = tmpElem; } } while(tmpElem = tmpElem.parentNode && tmpElem != this); if(initElem){ // tmpElem ne vaut pas false si on entre dans cette condition // donc l'élément recherché a été trouvé // on peut donc faire les traitement voulus }
Il est aussi à noter que la plupart des bibliothèques JavaScript permettent d'utiliser la délégation d'événement.
Par exemple pour jQuery, la syntaxe
permet de déléguer la gestion des événements clic sur les éléments ayant la classe CSS elems2 sur l'élément dont l'identifiant est elem1.
Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part $('#elem1').on('click', '.elems2', callback);
N'hésitez pas à indiquer dans les commentaires les différentes syntaxes pour les autres frameworks.