Å legge til hendelseshåndterere på nye elementer i JavaScript

La oss si at vi har en liste ul og en knapp:

html<ul>
  <li>element</li>
  <li>element</li>
  <li>element</li>
  <li>element</li>
  <li>element</li>
</ul>

<button>legg til</button>

La oss hente elementene våre i de tilsvarende variablene:

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

La oss gjøre det slik at når du klikker på en hvilken som helst li blir et utropstegn lagt til på slutten:

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

La oss nå gjøre det slik at når du trykker på knappen blir en ny li lagt til slutten av listen:

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

Vi vil imidlertid få et problem: et klikk på den nye li som ble lagt til vil ikke føre til at et utropstegn blir lagt til på slutten. Grunnen er at vi legger til en klikk-håndterer kun på de li-ene som eksisterte fra starten, men ikke på de nye.

La oss rette problemet ved å legge til en klikk-håndterer på den nye li:

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'element';
  
  item.addEventListener('click', function() { // klikk-håndterer
    this.textContent = this.textContent + '!';
  });
  
  list.appendChild(item);
});

Imidlertid blir nå koden for håndtererfunksjonen duplisert på to steder - for de opprinnelige li-ene og for de nye. La oss rette dette ved å flytte den til en egen funksjon:

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

La oss bruke funksjonen vår for å unngå kodeduplisering:

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

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

Oppgaven er egentlig løst og vi har unngått duplisering av håndtererfunksjonen. Imidlertid må vi fortsatt legge til hendelseshåndterere på to steder: både i løkken for eksisterende li, og ved klikk på knappen. I neste leksjon skal vi se på en måte å bli kvitt denne ulempen.