form
을 이용해서 개선할 수 있다.<form>
<input type="text" />
<button type="submit">
<i class="fas fa-plus-circle"></i>
</button>
</form>
// main.js
import { makeItem } from "./action.js";
const itemList = document.querySelector("ul");
const addBtn = document.querySelector("button");
const itemInput = document.querySelector("input");
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
try {
e.preventDefault();
const item = makeItem(itemList, itemInput);
itemList.appendChild(item);
itemInput.value = "";
} catch (error) {
console.log("아이템이 중복되어 리스트에 담을 수 없습니다😱");
}
});
itemList.addEventListener("click", (e) => {
const id = e.target.dataset.id;
const nodeName = e.target.nodeName;
if (id && nodeName === "I") {
const deleteItem = document.querySelector(`li[data-id="${id}"]`);
deleteItem.remove();
}
});
우선 HTML 코드에 form
태그를 추가하였다. form
태그를 활용하면 엔터키를 입력하는 이벤트 핸들러와 버튼을 클릭하는 이벤트 핸들러를 각각 등록하지 않고 submit
이벤트를 이용해서 이벤트 핸들러를 하나만 등록할 수 있다.
앞전에 설명한 것처럼 submit
이벤트는 기본적으로 발생 시, 페이지를 새로 로딩하기 때문에 preventDefault
메서드를 사용했다.
그리고 이전에는 자식 요소인 deleteBtn
에 이벤트 핸들러를 등록해서 아이템을 삭제할 수 있게끔 구현했지만 이벤트 위임
을 활용해서 부모 노드인 itemList
에 이벤트 핸들러를 등록하여 휴지통 아이콘을 클릭했을 때, 즉 자식 노드에 발생하는 이벤트를 부모 노드에서 처리할 수 있게끔 구현하였다.
여기서 data-XXX
라는 데이터 속성
을 활용하였다. 잠깐 짚고 넘어가자.
데이터 속성은 HTML 요소의 data-
로 시작하는 속성이다. 이러한 데이터 속성의 목적은 특정한 데이터를 DOM 요소에 저장해두기 위함이다. 개발자는 요소에 특정한 데이터를 저장하고 싶은 경우 자유롭게 사용할 수 있다.
// action.js
let id = 0;
export const makeItem = (itemList, itemInput) => {
itemInput.focus();
if (!itemInput.value) {
alert("아이템을 입력해주세요!");
} else {
if (checkDuplicate(itemInput.value, itemList)) {
alert("이미 추가되었습니다!");
} else {
const li = document.createElement("li");
li.setAttribute("data-id", id);
li.innerHTML = `
<h4>${itemInput.value}</h4>
<i class="fas fa-trash" data-id=${id}></i>
`;
id++;
return li;
}
}
};
export const checkDuplicate = (value, itemList) => {
return Array.from(itemList.childNodes).some((li) => value === li.innerText);
};
아이템을 생성해주는 기능을 담당하는 코드이다. 코드를 보면 data-id
라는 데이터 속성을 사용한 것이 보인다.
데이터 속성을 사용한 이유는 각각의 아이템들을 고유의 값은 data-id
로 분류할 수 있고, 이것을 DOM 요소로 개발자의 의도에 맞게 조작할 수 있기 때문이다.
또한 부모 노드인 itemList
에서 발생하는 모든 이벤트들 중에 휴지통 아이콘이 클릭되었을 경우에만 아이템을 지워주기 위해서 휴지콘 아이콘에 데이터 속성을 부여하였다.
데이터 속성은 DOM 객체의 dataset
속성을 참조해서 확인할 수 있다.
main.js 코드에서 e.target.dataset.id
를 통해 내가 지정한 데이터 속성 값인 data-id
에 접근하는 것을 확인할 수 있다. 따라서 data-id
를 지정한 노드 요소이면서 노드의 이름이 I, 즉 아이콘이면 data-id
를 속성으로 갖는 li
요소를 선택자로 지정하여 remove
메서드로 요소를 삭제한다.
이벤트 리스너를 두 번 중복해서 등록하는 것에 찝찝함을 느꼈었는데 form
태그를 활용해 이를 해결할 수 있어서 좋았다. 그리고 자식 노드에 일일히 이벤트를 등록하는 것이 아니라 부모 노드에서 자식 노드의 이벤트를 처리할 수 있으면 처리하게끔 로직을 구성하는 것이 조금 더 우아하게 코드를 짤 수 있겠다는 생각이 들었다.