Atașarea handler-elor pe elemente noi în JavaScript

Să presupunem că avem o listă ul și un buton:

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

<button>add</button>

Obținem elementele noastre în variabilele corespunzătoare:

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

Să facem ca la click pe orice li să i se adauge un semn de exclamare la sfârșit:

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

Acum să facem ca la apăsarea butonului să se adauge un nou li la sfârșitul listei:

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

Cu toate acestea, vom obține o problemă: click-ul pe noul li adăugat nu va duce la adăugarea semnului de exclamare la sfârșit. Fapt este că noi adăugăm handler-ul de click doar pe acele li care existau inițial, dar nu și pe cele noi.

Să remediem problema, atașând pe noul li un handler de click:

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

Cu toate acestea, acum codul funcției-handler este duplicat în două locuri - pentru li care existau inițial și pentru cele noi. Să remediem asta, extrăgându-l într-o funcție separată:

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

Folosim funcția noastră pentru a evita duplicarea codului:

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

Problema este în general rezolvată și am evitat duplicarea codului funcției-handler. Cu toate acestea, să atașăm handler-ele de evenimente tot trebuie în două locuri: atât în buclă pentru li existente, cât și la click pe buton. În lecția următoare vom analiza o metodă de a scăpa de acest neajuns.