Aggiunta di gestori di eventi a nuovi elementi in JavaScript

Supponiamo di avere una lista ul e un pulsante:

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

<button>add</button>

Otteniamo i nostri elementi nelle variabili corrispondenti:

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

Facciamo in modo che cliccando su qualsiasi li venga aggiunto un punto esclamativo alla fine:

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

Ora facciamo in modo che cliccando sul pulsante venga aggiunto un nuovo li alla fine della lista:

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

Tuttavia, incontreremo un problema: cliccando sul nuovo li aggiunto non verrà aggiunto il punto esclamativo alla fine. Il fatto è che aggiungiamo il gestore del click solo sulle li che esistevano inizialmente, ma non su quelle nuove.

Risolviamo il problema, aggiungendo alla nuova li il gestore del click:

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

Tuttavia, ora il codice della funzione di gestione è duplicato in due punti - per le li esistenti inizialmente e per quelle nuove. Risolviamo questo, estraendolo in una funzione separata:

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

Usiamo la nostra funzione per evitare la duplicazione del codice:

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);
});

Il problema è in generale risolto e abbiamo evitato la duplicazione del codice della funzione di gestione. Tuttavia, dobbiamo comunque aggiungere i gestori di eventi in due punti: sia nel ciclo per le li esistenti, sia al click sul pulsante. Nella prossima lezione esamineremo un modo per sbarazzarci di questa scomodità.