Додавање обработувачи на нови елементи во JavaScript

Да претпоставиме дека имаме листа ul и копче:

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

<button>add</button>

Ги добиваме нашите елементи во соодветните променливи:

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

Да направиме така што при клик на било која li да и се додаде извичник на крајот:

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

Сега да направиме така што при клик на копчето на крајот од листата да се додаде нова li:

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

Сепак, ќе наидеме на проблем: кликот на новододадената li нема да резултира со додавање на извичник на крајот. Проблемот е што ние го додаваме обработувачот на клик само на оние li кои постоеја иницијално, но не и на новите.

Да го поправиме проблемот, со додавање обработувач на клик на новата li:

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'item';
  
  item.addEventListener('click', function() { // обработувач на клик
    this.textContent = this.textContent + '!';
  });
  
  list.appendChild(item);
});

Сепак, сега кодот на функцијата-обработувач се дуплира на две места - за постојните li и за новите. Да го исправиме ова, со тоа што ќе ја издвоиме функцијата посебно:

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

Ја користиме нашата функција, за да избегнеме дуплирање на кодот:

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

Проблемот е решен и избегнавме дуплирање на кодот на функцијата-обработувач. Сепак, да додаваме обработувачи на настани сè уште мораме на две места: и во циклусот за постојните li, и при клик на копчето. Во следната лекција ќе разгледаме начин како да се ослободиме од ова непријатност.