[Javascript] 동적 생성한 요소에 이벤트 추가하기 (addEventListener)

todo-list 삭제 버튼에 추가한 이벤트가 제대로 적용되는지 확인하려는데 html 파일을 실행하자마자 콘솔에 빨간 불이 들어왔다.

미리 버튼을 추가해두고 테스트했을 때는 발생하지 않았는데, 기존에 있던 테스트용 요소들을 모두 지우고 실행했을 때 발생하는 것으로 보아 addEventListener는 버튼이 생기기도 전에 호출되는데 해당 아이디를 가진 object가 없으니 이런 오류가 나는구나 추측이 됐다.

 

 

알아야 할 것

동적으로 생성한 요소에 이벤트를 추가하기 위해 생각해야하는 것은 다음과 같다.

1) addEventListener는 EventTarget 인터페이스의 메서드로, 가장 일반적으로 DOM 객체에 어떤 이벤트가 발생했을 때 어떤 동작을 수행할지 설정하는 기능을 한다.

2) createElement를 통해 DOM 객체를 생성할 수 있다.

 

사실 1)만 정확하게 알았어도 덜 헤맸을 것 같다..

내가 사용하는 메서드가 무슨 일을 하는지 정확히 아는 것이 중요하다는 생각이 들었다.

 

 

처음 시도한 방법

// task 추가
const taskAddButton = document.querySelector('#taskAddButton');
taskAddButton.addEventListener("click", addTask);

const taskList = document.querySelector('#list');
const taskInput = document.querySelector('#taskInput');
function addTask() {
    let newTask = taskInput.value;
    console.log(taskList.children.length + 1);
    let newLi = `
    <li class="task">
        <input type="checkbox" name="task" id="task${taskList.children.length + 1}">
        <label for="task${taskList.children.length + 1}">${newTask}</label>
        <button class="taskDeleteButton"></button>
    </li>
    `;

    taskList.innerHTML += newLi;
    taskInput.value = '';
}

// task 삭제
const taskDeleteButton = document.querySelector('.taskDeleteButton');
taskDeleteButton.addEventListener("click", deleteTask);

function deleteTask(e) {
    e.target.parentElement.remove();
}

 

제일 처음 작성했던 방법이다. 처음 파일을 실행하면 taskDeleteButton 클래스를 가진 요소가 없기때문에 오류가 발생한다.

저 상태로의 버튼은 단순히 문자열의 일부인데, addEventListener를 추가하기 위해 어떻게 DOM 객체로 받을 수 있을지 고민했다.

 

 

바꾼 방법

// task 추가
const taskAddButton = document.querySelector('#taskAddButton');
taskAddButton.addEventListener("click", addTask);

const taskList = document.querySelector('#list');
const taskInput = document.querySelector('#taskInput');
function addTask() {
    let newTask = taskInput.value;

    let newLi = document.createElement('li');
    newLi.className = "task";
    newLi.innerHTML = `
        <input type="checkbox" name="task" id="task${taskList.children.length + 1}">
        <label for="task${taskList.children.length + 1}">${newTask}</label>
    `;

    let deleteButton = document.createElement('button');
    deleteButton.className = "taskDeleteButton";
    deleteButton.addEventListener("click", deleteTask);
    
    newLi.appendChild(deleteButton);
    taskList.appendChild(newLi);

    taskInput.value = '';
}

// task 삭제
function deleteTask(e) {
    e.target.parentElement.remove();
}

 

새로운 할 일을 입력했을 때 html 요소를 문자열로 추가하던 방식에서 DOM 객체를 생성해 추가하는 방식으로 변경했다!

그리고 생성한 DOM 객체를 받아 이벤트를 설정해준 뒤 할일 목록에 추가해줬다.

 

목표대로 기능이 구현됐다!

 

 

정리

1) 요소를 생성할 때 문자열 -> html으로 변환하며 추가하지 않고 EventTarget이 구현되어있는 DOM 객체로 생성한다.

2) 생성한 객체에 이벤트를 설정한다.

 

* 이벤트 설정 -> 원하는 위치에 추가 / 원하는 위치에 추가 -> 이벤트 설정 순서는 상관없다! 이미 생성된 객체를 변수에 받아두었기 때문이다.

 

 

참고자료

MDN, EventTarget.addEventListener()

 

EventTarget.addEventListener() - Web API | MDN

EventTarget 인터페이스의 addEventListener() 메서드는 지정한 유형의 이벤트를 대상이 수신할 때마다 호출할 함수를 설정합니다.

developer.mozilla.org