Marius C.
Marius C.

Reputation: 47

My remove event listener gives me an error

I created a dummy todo-list (please don't mind the bad design/responsiveness).

It works good, I can add items, I can delete by selection, or delete all of them at once. The problem is at the last one, it works, but it gives me an error:

Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node. at HTMLButtonElement. (http://127.0.0.1:5500/scripts.js:46:26)

One thing I observed is that the first time I remove all elements it doesn't give me this error, but if I try again it will give me that error. (even if the action itself works).

HTML/JS

const add = document.querySelector('.add-item');
const remove = document.querySelector('.remove-item');
const nameList = document.querySelector('.todo-list');
const textField = document.querySelector('.text');

//main event listener
add.addEventListener('click', function() {

        //conditions
        if (textField.value === '') {
            alert('The textfield is empty!');
            return;
        }

        //creating elements
        const newDiv = document.createElement('div');
        const newLi = document.createElement('li');
        const liContent = document.createTextNode(textField.value);
        const closeButton = document.createElement('div');
        const closeButtonContent = document.createTextNode('Delete item');


        //appending elements
        newLi.appendChild(liContent);
        newDiv.appendChild(newLi);
        newDiv.appendChild(closeButton);
        closeButton.appendChild(closeButtonContent);

        //adding classes
        newDiv.classList.add('todo-div');
        closeButton.classList.add('todo-close');

        //output
        nameList.appendChild(newDiv);
        textField.value = '';


        closeButton.addEventListener('click', function () {
            if (newDiv.className === 'todo-div') {
                nameList.removeChild(newDiv);
            }
        });

        remove.addEventListener('click', function() {
            if (newDiv.className === 'todo-div') {
                nameList.removeChild(newDiv);
            }
        })
});
body {
    background-color: #f4d9c6;
}

.text {
    position: absolute;
    top: 20%;
    left: 45%;
    transform: translate(-50%, -50%);
    width: 350px;
    height: 30px;
    outline: none;
    border: 1px solid #bea695
}

.add-item {
    position: absolute;
    top: 20%;
    left: 56%;
    transform: translate(-50%, -50%);
}

.remove-item {
    position: absolute;
    top: 20%;
    left: 60%;
    transform: translate(-50%, -50%);
}

.todo-div {
    background-color: grey;
    width: 250px;
    display: flex;
    justify-content: space-between;
    list-style-type: none;
}

.todo-close {
    background-color: red;
}
<!DOCTYPE html>
<html>
<head>
    <title>Page</title>
    <link rel="stylesheet" href="styles.css" type="text/css">
</head>
<body>
    <ul class="todo-list">
        <div class="container"></div>
        <input class="text" type="text">
        <button class="add-item">Add</button>
        <button class="remove-item">Remove </button>
    </ul>
    <script src="scripts.js"></script>
</body>
</body>
</html>

Upvotes: 0

Views: 368

Answers (1)

Ouroborus
Ouroborus

Reputation: 16896

        remove.addEventListener('click', function() {
            if (newDiv.className === 'todo-div') {
                nameList.removeChild(newDiv);
            }
        })

This event handler is added every time a div is added but, when the remove button is clicked, the event handler isn't removed from the button. This means that, later, all those event handlers still fire even though the div they're meant to target doesn't exist any more.

One way to fix this is to use a single event handler for the remove button that removes all the relevant divs if there are any. You'll also need to move it outside of your "main event listener".

    remove.addEventListener('click', function() {
        Array.from(nameList.children).forEach(element => {
            if (element.className === 'todo-div') {
                nameList.removeChild(element);
            }
        }
    })

    //main event listener
    add.addEventListener('click', function() {
    // ...

Upvotes: 1

Related Questions