Notikumu apstrādātāju pievienošana jauniem elementiem JavaScript

Pieņemsim, ka mums ir saraksts ul un poga:

html<ul>
  <li>vienība</li>
  <li>vienība</li>
  <li>vienība</li>
  <li>vienība</li>
  <li>vienība</li>
</ul>

<button>pievienot</button>

Iegūstam mūsu elementus attiecīgajos mainīgajos:

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

Uztaisīsim tā, lai, noklikšķinot uz jebkuras li tās beigās tiktu pievienots izsaukuma zīme:

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

Tagad uztaisīsim tā, lai, nospiežot uz pogas, saraksta beigās tiktu pievienota jauna li:

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

Tomēr mēs iegūsim problēmu: klikšķis uz jauni pievienoto li neizraisīs izsaukuma zīmes pievienošanu beigās. Lieta tāda, ka mēs pievienojam klikšķa apstrādātāju tikai tiem li, kuri pastāvēja sākotnēji, bet ne jaunajiem.

Izlabosim problēmu, pievienojot jaunajai li klikšķa apstrādātāju:

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = 'vienība';
  
  item.addEventListener('click', function() { // klikšķa apstrādātājs
    this.textContent = this.textContent + '!';
  });
  
  list.appendChild(item);
});

Tomēr tagad apstrādātāja funkcijas kods tiek dublēts divās vietās - sākotnēji pastāvošajām li un jaunajām. Izlabosim to, izņemot to atsevišķā funkcijā:

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

Izmantosim mūsu funkciju, lai izvairītos no koda dublēšanas:

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

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

Problēma kopumā ir atrisināta un mēs esam izvairījušies no apstrādātāja funkcijas koda dublēšanas. Tomēr, pievienot notikumu apstrādātājus mums tik un tā nākas divās vietās: gan cilpā esošajām li, gan, noklikšķinot uz pogas. Nākamajā nodarbībā mēs apskatīsim veidu, kā atbrīvoties no šīs neērtības.