Attacher des gestionnaires d'événements aux nouveaux éléments en JavaScript

Supposons que nous ayons une liste ul et un bouton :

html<ul>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

<button>add</button>

Récupérons nos éléments dans les variables correspondantes :

javascriptlet button = document.querySelector('button');
let list   = document.querySelector('ul');
let items  = list.querySelectorAll('li');

Faisons en sorte qu'un clic sur n'importe quelle li ajoute un point d'exclamation à la fin :

javascriptfor (let item of items) {
  item.addEventListener('click', function() {
    this.textContent = this.textContent + '!';
  });
}

Faisons maintenant en sorte qu'un clic sur le bouton ajoute une nouvelle li à la fin de la liste :

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'item';
  list.appendChild(item);
});

Cependant, nous obtiendrons un problème : un clic sur la nouvelle li ajoutée n'ajoutera pas de point d'exclamation à la fin. Le fait est que nous ajoutons un gestionnaire de clic uniquement aux li qui existaient initialement, mais pas aux nouvelles.

Corrigeons le problème en attachant à la nouvelle li un gestionnaire de clic :

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'item';
  
  item.addEventListener('click', function() { // gestionnaire de clic
    this.textContent = this.textContent + '!';
  });
  
  list.appendChild(item);
});

Cependant, maintenant le code de la fonction gestionnaire est dupliqué à deux endroits - pour les li existant initialement et pour les nouvelles. Corrigeons cela en le extrayant dans une fonction séparée :

javascriptfunction handler() {
  this.textContent = this.textContent + '!';
}

Utilisons notre fonction pour éviter la duplication de code :

javascriptfor (let item of items) {
  item.addEventListener('click', handler);
}

button.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'item';
  
  item.addEventListener('click', handler);
  
  list.appendChild(item);
});

Le problème est en gros résolu et nous avons évité la duplication du code de la fonction gestionnaire. Cependant, nous devons toujours attacher les gestionnaires d'événements à deux endroits : à la fois dans la boucle pour les li existantes, et lors du clic sur le bouton. Dans la prochaine leçon, nous verrons un moyen de nous débarrasser de cette gêne.