JavaScript에서 새로운 요소에 이벤트 핸들러 추가하기

ul 목록과 버튼이 있다고 가정해 봅시다:

html<ul>
  <li>항목</li>
  <li>항목</li>
  <li>항목</li>
  <li>항목</li>
  <li>항목</li>
</ul>

<button>추가</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 = '항목';
  list.appendChild(item);
});

그러나 문제가 발생합니다: 새로 추가된 li를 클릭해도 끝에 느낌표가 추가되지 않습니다. 그 이유는 클릭 이벤트 핸들러를 처음부터 존재했던 li에만 추가했기 때문입니다. 새로운 요소에는 추가하지 않았습니다.

새로운 li에도 클릭 핸들러를 추가하여 문제를 해결해 봅시다:

javascriptbutton.addEventListener('click', function() {
  let item = document.createElement('li');
  item.textContent = '항목';
  
  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.addEventListener('click', handler);
  
  list.appendChild(item);
});

문제는 기본적으로 해결되었고 핸들러 함수 코드의 중복은 피했습니다. 그러나 여전히 이벤트 핸들러를 두 곳(기존 li를 위한 루프와 버튼 클릭 시)에 추가해야 합니다. 다음 강의에서는 이 불편함을 해결하는 방법을 알아보겠습니다.