Eseménykezelők hozzárendelése új elemekhez JavaScriptben

Tegyük fel, hogy van egy ul listánk és egy gombunk:

html<ul>
  <li>elem</li>
  <li>elem</li>
  <li>elem</li>
  <li>elem</li>
  <li>elem</li>
</ul>

<button>hozzáad</button>

Kapjuk meg elemeinket a megfelelő változókba:

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

Tegyük úgy, hogy bármelyik li elemre kattintáskor egy felkiáltójel kerüljön a végére:

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

Most tegyük úgy, hogy a gomb megnyomásakor egy új li kerüljön a lista végére:

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

Azonban egy problémába fogunk ütközni: egy újonnan hozzáadott li elemre kattintás *nem* fog vezetni egy felkiáltójel hozzáadásához a végéhez. Ennek az az oka, hogy a kattintás eseménykezelőjét csak azokra a li elemekre rendeltük, amelyek kezdetben léteztek, de *nem az újakra*.

Javítsuk a problémát úgy, hogy a kattintás eseménykezelőjét rárendeljük az új li elemre is:

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'elem';
  
  item.addEventListener('click', function() { // kattintás eseménykezelő
    this.textContent = this.textContent + '!';
  });
  
  list.appendChild(item);
});

Azonban most a kezelőfüggvény kódja megduplázódott két helyen - a kezdetben létező li elemekre és az újakra. Javítsuk ezt úgy, hogy kiemeljük egy külön függvénybe:

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

Használjuk a függvényünket a kóduplikálás elkerülésére:

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

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

A probléma alapvetően megoldódott, és elkerültük a kezelőfüggvény kódjának duplikálását. Azonban az eseménykezelők hozzárendelése továbbra is két helyen történik: a ciklusban a létező li elemekre, és a gombra kattintáskor. A következő leckében megvizsgálunk egy módot ennek a kényelmetlenségnek a megszüntetésére.