프론트엔드 첫걸음

[문제해결] 동적으로 추가한 HTML에 이벤트 붙이기 (insertAdjacentHTML, 이벤트 위임) 본문

개발 공부/Javascript

[문제해결] 동적으로 추가한 HTML에 이벤트 붙이기 (insertAdjacentHTML, 이벤트 위임)

차정 2022. 7. 20. 02:43

 버튼을 클릭할때마다 HTML이 특정 요소에 insert되어 화면에 보여지는 코드가 있을때 
동적으로 추가된 HTML에 이벤트를 붙이고 싶으면 어떻게 해야할까?

우선 이벤트를 달고싶으면 그 DOM 을 선택자로 골라내야하는데 그게 안된다.

querySelector가 HTML로 생성된 요소를 찾지 못했다.

콘솔에 바로 찍어보면 또 찍힌다 .

 

See the Pen Untitled by JEONG (@cona) on CodePen.

 

 

 

 

 

콘솔에 찍으면 또 찍힌다니까?!

 

codepen에서 확인할 수 있다시피 'DOMContentLoaded'를 사용하여 DOM이 모두 로드된 뒤에 해도 안된다.

let html = `<div id="item"> 생성되는 아이템 </div>`;

let $container = document.querySelector('#container');
let $btn = document.querySelector('button');
$btn.addEventListener('click',()=>{
  $container.insertAdjacentHTML('beforeend', html);
  
})
console.log(document.querySelector('#item'))


document.addEventListener('DOMContentLoaded', function () {
  //document 안의 이미지, js 파일 포함 전부 로드가 되었을 경우 실행할 코드  
 console.log('dom 로드 후에도 '+ document.querySelector('#item'))
});

 

 

 

 

이런 경우 이렇게 하면 된다.

See the Pen 이벤트위임 by JEONG (@cona) on CodePen.

 

 

 

"생성되는 아이템"을 클릭하면 요소가 출력되도록 하니까 event target으로 item이 아이디인 요소를 찾아냈다! 

dom 객체를 찾아냈으니 이제 얘를 지지고 볶고 할 수 있게 되었다!

 

 

 

이걸 이벤트 위임 이라고 한다.

이벤트 위임은 이벤트가 아래로 전파(이벤트 버블링)되는 점을 이용해서

상위 엘리먼트에서 이벤트 리스너를 관리하게 하는 것이다.

이벤트 위임을 하게되면 동적으로 생성되는 코드에 이벤트핸들러를 달아줄 수 있으며, 

상위요소에서 이벤트를 관리하므로 관리가 쉬워지고, 이벤트 리스너가 사용하는 총 메모리 공간이 줄어든다는 장점이 있다.

 

 

 

 

[출처]

https://stackoverflow.com/questions/34896106/attach-event-to-dynamic-elements-in-javascript

https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation%EF%BB%BF

 

[읽어보면 좋을 글]

https://ui.toast.com/weekly-pick/ko_20160826

https://ko.javascript.info/event-delegation

 

 

 

tmi)   인생 첫 이벤트 위임 코드 

let localStorage_cart = [];

document.addEventListener('click', function (e) {
  if (e.target && Object.keys(e.target.dataset).includes('buyButton')) {
    let itemId = e.target.closest('[data-item]').dataset.itemId;
    localStorage_cart.indexOf(itemId) < 0
      ? localStorage_cart.push(itemId)
      : null;
    localStorage.setItem('cart', JSON.stringify(localStorage_cart));
   //console.log(JSON.parse(localStorage.getItem('cart')));
  }
});

회사 다닐 때는 setTimeout으로 몇 초 후에 요소를 찾는 방법을 썼었다. 개인적으로 이렇게 하는 게 더 나은 것 같다.

문제를 해결해가면서 몰랐던 것을 알게되니 기쁘다.