Uusien elementtien käsittelijöiden liittäminen JavaScriptissä

Oletetaan, että meillä on lista ul ja painike:

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

<button>add</button>

Haetaan elementtimme vastaaviin muuttujiin:

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

Tehdään niin, että minkä tahansa li:n napsautuksessa siihen lisätään huutomerkki loppuun:

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

Tehdään nyt niin, että painiketta painettaessa listan loppuun lisätään uusi li:

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

Saamme kuitenkin ongelman: uuden lisätyn li:n napsautus ei johda huutomerkin lisäämiseen loppuun. Asia on siinä, että lisäämme napsautuksen käsittelijän vain niille li-elementeille, jotka olivat olemassa alun perin, mutta ei uusille.

Korjataan ongelma liittämällä uuteen li:hin napsautuksen käsittelijä:

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

Nyt kuitenkin käsittelijäfunktion koodi toistuu kahdessa paikassa - alkuperäisille li-elementeille ja uusille. Korjataan tämä erottamalla se omaksi funktiokseen:

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

Käytetään funktiotamme välttääksemme koodin toistoa:

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

Ongelma on periaatteessa ratkaistu ja vältyimme käsittelijäfunktion koodin toistamiselta. Kuitenkin tapahtumakäsittelijöiden liittäminen on edelleen tehtävä kahdessa paikassa: sekä silmukassa olemassa oleville li-elementeille että painikkeen napsautuksen yhteydessä. Seuraavassa oppitunnissa käsittelemme tavan päästä eroon tästä epämukavuudesta.