[Day17] 이벤트 위임 (20240716)

2024. 7. 16. 18:08공부/DGTP TIL

<body>
    <section class="section-center">
        <!-- form -->
        <form class="grocery-form">
            <p class="alert"></p>
            <h3>grocery bud</h3>
            <div class="form-control">
                <input type="text" id="grocery" placeholder="e.g. eggs" />
                <button type="submit" class="submit-btn">submit</button>
            </div>
        </form>
        <!-- list -->
        <div class="grocery-container">
            <div class="grocery-list"></div>
            <button class="clear-btn">clear items</button>
        </div>
    </section>
    <script src="app.js"></script>
</body>

위와같은 foodlist라는 html이 존재한다.

app.js를 요약하자면, form에 원하는 텍스트를 입력하여 버튼을 누르면 div에 새로운 food가 리스트 형태로 나타나며 각각의 food에는 삭제, 수정 버튼이 존재한다.

리스트 제일 밑에는 clear 버튼이 존재한다. 

 

// add item
function addItem(e) {
    e.preventDefault();
    const value = grocery.value;
    const id = new Date().getTime().toString();
    if (value !== "" && !editFlag) {
        const element = document.createElement("article");
        let attr = document.createAttribute("data-id");
        attr.value = id;
        element.setAttributeNode(attr);
        element.classList.add("grocery-item");
        element.innerHTML = `<p class="title">${value}</p>
 <div class="btn-container">
 <!-- edit btn -->
 <button type="button" class="edit-btn">
 <i class="fas fa-edit"></i>
 </button>
 <!-- delete btn -->
 <button type="button" class="delete-btn">
 <i class="fas fa-trash"></i>
 </button>
 </div>
 ;`
        // add event listeners to both buttons;
        const deleteBtn = element.querySelector(".delete-btn");
        deleteBtn.addEventListener("click", deleteItem);
        const editBtn = element.querySelector(".edit-btn");
        editBtn.addEventListener("click", editItem);
        // append child
        list.appendChild(element);
        // display alert
        displayAlert("item added to the list", "success");
        // show container
        container.classList.add("show-container");
        // set local storage
        addToLocalStorage(id, value);
        // set back to default
        setBackToDefault();
    } else if (value !== "" && editFlag) {
        editElement.innerHTML = value;
        displayAlert("value changed", "success");
        // edit local storage
        editLocalStorage(editID, value);
        setBackToDefault();
    } else {
        displayAlert("please enter value", "danger");
    }
}

// delete item
function deleteItem(e) {
    const element = e.currentTarget.parentElement.parentElement;
    const id = element.dataset.id;
    list.removeChild(element);
    if (list.children.length === 0) {
        container.classList.remove("show-container");
    }
    displayAlert("item removed", "danger");
    setBackToDefault();
    // remove from local storage
    removeFromLocalStorage(id);
}
// edit item
function editItem(e) {
    const element = e.currentTarget.parentElement.parentElement;
    // set edit item
    editElement = e.currentTarget.parentElement.previousElementSibling;
    // set form value
    grocery.value = editElement.innerHTML;
    editFlag = true;
    editID = element.dataset.id;
    //
    submitBtn.textContent = "edit";
}

변경 전 -> 개별 요소에 대한 이벤트 리스너

 

// event delegation for edit and delete buttons
list.addEventListener("click", function(e) {
    if (e.target.classList.contains("delete-btn") || e.target.parentElement.classList.contains("delete-btn")) {
        deleteItem(e);
    }
    if (e.target.classList.contains("edit-btn") || e.target.parentElement.classList.contains("edit-btn")) {
        editItem(e);
    }
});

// delete item
function deleteItem(e) {
    const element = e.target.closest(".grocery-item");
    const id = element.dataset.id;
    list.removeChild(element);
    if (list.children.length === 0) {
        container.classList.remove("show-container");
    }
    displayAlert("item removed", "danger");
    setBackToDefault();
    // remove from local storage
    removeFromLocalStorage(id);
}

// edit item
function editItem(e) {
    const element = e.target.closest(".grocery-item");
    // set edit item
    editElement = element.querySelector(".title");
    // set form value
    grocery.value = editElement.innerHTML;
    editFlag = true;
    editID = element.dataset.id;
    //
    submitBtn.textContent = "edit";
}

각각의 버튼에 연결되는 대신, 상위 list요소에 연결된다.
함수 또한 대상 요소를 올바르게 식별하게 변화

 

-> 이벤트 리스너 수가 적어 메모리 사용량이 감소하여 성능 최적화 달성