JavaScript

동일한 className을 사용하는 HTML 요소의 이벤트 처리

Happy._. 2024. 4. 18. 09:52

Q 어떤 문제가 있었는지

미니 프로젝트의 방명록 페이지 구현에서 수정 버튼과 삭제 버튼의 클릭 이벤트가 버튼을 두 번 클릭했을 때 작동하는 문제가 있었다.

수정 버튼과 삭제 버튼을 구현한 코드는 다음과 같다.

document.addEventListener("click", async (e) => {
  if (e.target.className === "delete") {
    const deleteItems = document.querySelectorAll(".delete");

    deleteItems.forEach((item) => {
      item.addEventListener("click", async function () {
      
      	// 삭제에 대한 처리      
      });
    });
  }

  if (e.target.className === "insert") {
    const insertItems = document.querySelectorAll(".insert");

    insertItems.forEach((item) => {
      item.addEventListener("click", function () {
      
      	// className이 "insert"인 여러 요소(태그) 중 "click" 이벤트가 발생한 요소에 대한 처리
      });
    });
  }

  if (e.target.className === "update") {
  
    // 수정된 방명록의 텍스트를 인식해서 firebase.js로 넘기는 코드
  }
});

 

코드를 이렇게 작성한 이유는 이전 ITL에 남긴 기록과 같이 데이터를 불러오면서 동적으로 태그를 삽입하는 방식이고 동일한 className을 사용하기 때문에 단일 요소의 이벤트 처리 방법인 document.querySelector().addEventListener()로 이벤트를 처리를 할 수 없었고 위와 같이 querySelectorAll()을 사용하여 className이 'delete'인 요소들을 가져와서 그 중 'click' 이벤트가 발생한 요소에 대한 처리를 해야 했다.

Q 내가 시도해본 것들

  • log로 클릭 이벤트가 정상적으로 동작하는지 확인(log는 두 번 출력되지만 이벤트는 두 번째 클릭에서 발생함)
  • document.addEventListener에서 window.addEventListener로 변경해봤지만 동일
  • window.addEventListener("DOMContentLoaded", listener)에 delete에 대한 addEventListener 추가(동작 X)

Q 어떻게 해결했는지

window.addEventListener("DOMContentLoaded", listener) 안에서 DOM load 후 내부에서 추가 이벤트 리스너 구현없이 document.querySelectorAll().forEach()를 추가했다.

window.addEventListener("DOMContentLoaded", async () => {
  /*
  생략된 코드
  - 쿠키를 확인하고 사용자 아이디가 없으면 로그인 페이지로 이동 코드
  - DOM load 후 Cloud Firestore에서 데이터를 받아오는 코드
  */

  const deleteItems = document.querySelectorAll(".delete");
  deleteItems.forEach((item) => {
    item.addEventListener("click", async function () {
      
      // 로그인된 사용자와 작성자가 일치하는지 확인 후 삭제하는 코드
    });
  });

  const insertItems = document.querySelectorAll(".insert");
  insertItems.forEach((item) => {
    item.addEventListener("click", function () {
      
      // 로그인된 사용자와 작성자가 일치하는지 확인 후 수정하는 코드
    });
  });
});

document.addEventListener("click", async (e) => {
  if (e.target.className === "update") {
  
    // 수정된 방명록의 텍스트를 인식해서 firebase.js로 넘기는 코드
  }
});

 

삭제 로직에 이벤트 타겟의 this를 사용하여 코드를 작성했을 때, this를 console에 출력하면 다음과 같이 출력된다.


Q 뭘 새롭게 알았는지

  • 같은 className을 갖고 있는 요소들에 이벤트를 적용할 때 document.querySelectorAll().forEach()를 사용한다.
  • forEach()내 forEach((item) => { item.addEventListener("click", async function () { ... }와 같이 요소들에 이벤트가 적용되므로 상위에 이벤트 리스너를 더 추가할 필요가 없다.
  • DOM load 후 이벤트 처리를 위해서는 window.addEventListener("DOMContentLoaded", listener)를 사용한다.

참고 링크

'JavaScript' 카테고리의 다른 글

[JavaScript] fetch  (0) 2024.06.03
[JavaScript] URL에서 쿼리 문자열 추출 방법(URLSearchParams)  (1) 2024.04.18
DOM Node에 #text가 추가되는 이유  (0) 2024.04.17
JavaScript의 Module  (0) 2024.04.16