0

I am trying to create a todolist type webpage and I ran into this problem. Basically when I change or update the list element, the list does not get updated and is still looping through the first 2 buttons in its default html

index.html:

<body>
    <script src="script.js" defer></script>
    <link href="styles.css">

    <div id="essentials"></div>
        <h2>ToDoList</h2>
        <input id="essentialInput">
        <button id="addTask">Add Task</button>
    </div>
    <list id="list">
        <h3 id="0">something epic <button class="deleteButton" id="0">Delete</button></h3>
        <h3 id="1">Something else <button class="deleteButton" id="1">Delete</button></h3>
    </list>
</body>

script.js:

const essentialInput = document.getElementById('essentialInput')
const addTaskButton = document.getElementById('addTask')
const list = document.getElementById('list')
let button = document.querySelectorAll('.deleteButton')
addTaskButton.addEventListener('click', function() {
    text = essentialInput.value

    if(text == null) return "Nothing in input field"

    children = list.childElementCount
    list.innerHTML += `<h3 id=${children}>${text} <button class="deleteButton" id=${children}>Delete</button></h3>`
})

for(let i = 0; i<button.length; i++) {
    button[i].addEventListener('click', function() {
        console.log(button[i].id)
    })
}

I know the issue but I dont know how to fix it. I've tried to put the button eventListeners in a change event listener for when the list changes but then nothing happens until I click a delete button.

SoulDaMeep
  • 57
  • 6

1 Answers1

2

The problem is that using the += operator on an element's innerHTML is NOT just concatenating the new HTML... It wholy replaces it with the result.

That is why you were loosing the listeners already set on the two first <h3>.

Then, the new <h3> never had any listeners on them.

So the solution for this case is to register the event listener on the static parent on behalf of its childrens... And take advantage of event bubbling. That is called event delegation.

const essentialInput = document.getElementById('essentialInput')
const addTaskButton = document.getElementById('addTask')
const list = document.getElementById('list')
let button = document.querySelectorAll('.deleteButton')
addTaskButton.addEventListener('click', function() {
    text = essentialInput.value

    if(text == null) return "Nothing in input field"

    children = list.childElementCount
    list.innerHTML += `<h3 id=${children}>${text} <button class="deleteButton" id=${children}>Delete</button></h3>`
})

// Add the event listener on the static parent
list.addEventListener("click", function(e){
  if(e.target.classList.contains("deleteButton")){
    console.clear()
    console.log(e.target.id)
  }
})
<body>
    <script src="script.js" defer></script>
    <link href="styles.css">

    <div id="essentials"></div>
        <h2>ToDoList</h2>
        <input id="essentialInput">
        <button id="addTask">Add Task</button>
    </div>
    <list id="list">
        <h3 id="0">something epic <button class="deleteButton" id="0">Delete</button></h3>
        <h3 id="1">Something else <button class="deleteButton" id="1">Delete</button></h3>
    </list>
</body>
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
  • 1
    I'd just use `list.append()` instead of overwriting the HTML every time. Would still use event delegation though – Phil Feb 16 '22 at 04:25