Search code examples
javascriptarraysdomonclicksplice

How to delete a DOM element from an array after you've clicked on it?


I was making a simple to-do list. You submit itens from an input and they go to the To-DO section. When you click over them they go to the 'Done' section. And when you click on them again, they vanish forever. It was all working fine.

But I realized the doneItens array kept growing in length, which I wanted to optimize. So I came up with this line of code

        doneItens.splice(i, 1);

which goes inside an onclick event, which you can see in the code inside the deleteDone function.

That gives the error, though,

Error:{
  "message": "Uncaught TypeError: doneItens.splice is not a function"

If I put it outside and below the onclick event it also doesn't work. How can I do it?

var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');

function handleSubmit(event) {
    event.preventDefault();
    const newItem = document.createElement('li');
    newItem.setAttribute('class', 'item');
    newItem.append(input.value);
    toDo.append(newItem);
    input.value='';

    deleteItem();
}

function deleteItem() {
    const toBeDone = document.getElementsByClassName('item');
    for(let i = 0; i < toBeDone.length; i++) {
        toBeDone[i].onclick = () => {
            appendItemDone(toBeDone[i]);
            toBeDone[i].style.display = 'none';
            deleteDone();
        } 
    }   
}

function appendItemDone(item) {
        const newDone = document.createElement('li');
        newDone.setAttribute('class', 'feito')
        newDone.append(item.innerText);
        done.append(newDone);

}

function deleteDone() {
    const doneItens = document.getElementsByClassName('feito');
    console.log('done length', doneItens.length)
    for (let i = 0; i < doneItens.length; i++) {
        doneItens[i].onclick = () => {
            doneItens[i].style.display = 'none';
            doneItens.splice(i, 1);
        }
    }
}
<div id='flex'>
        <form class='form' onsubmit='handleSubmit(event)'>
            <input placeholder='New item' type='text' id='play'>
            <button>Send</button>
        </form>
        <div id='left'> 
            <h1 id='todo' >To-do:</h1>
            <p class='instruction'><i>(Click over to mark as done)</i></p>
            <ol id='here'></ol>
        </div>
    
        <div id='right'>
            <h1>Done:</h1>
      <p class='instruction'><i>(Click over to delete it)</i></p>
            <p id='placeholder'></p>
            <ol id='done'></ol>
        </div>
    </div>


Solution

  • With the use of JavaScript DOM API such as Node.removeChild(), Element.remove() and Node.parentNode, your task can be solved with this code:

    const input = document.getElementById('play');
    const todo = document.getElementById('todo');
    const done = document.getElementById('done');
    
    function handleSubmit(event) {
      event.preventDefault();
    
      // create new "todo" item
      const newTodo = document.createElement('li');
      newTodo.textContent = input.value;
      todo.append(newTodo);
    
      // clean the input field
      input.value = '';
    
      // listen to "click" event on the created item to move it to "done" section
      newTodo.addEventListener('click', moveToDone);
    }
    
    function moveToDone(event) {
      // remove "click"-listener to prevent event listener leaks
      event.target.removeEventListener('click', moveToDone);
    
      // move clicked todo-element to "done" section
      const newDone = event.target.parentNode.removeChild(event.target);
      done.append(newDone);
    
      // listen to "click" event on the moved item to then completely delete it
      newDone.addEventListener('click', removeFromDone);
    
      debugElementsLeak();
    }
    
    function removeFromDone(event) {
      // remove "click"-listener to prevent event listener leaks
      event.target.removeEventListener('click', removeFromDone);
    
      // complete remove clicked element from the DOM
      event.target.remove();
    
      debugElementsLeak();
    }
    
    function debugElementsLeak() {
      const todoCount = todo.childElementCount;
      const doneCount = done.childElementCount;
      console.log({ todoCount, doneCount });
    }
    <div id="flex">
      <form class="form" onsubmit="handleSubmit(event)">
        <input placeholder="New item" type="text" id="play">
        <button>Add item</button>
      </form>
    
      <div id="left">
        <h1>To-do:</h1>
        <p class="instruction"><em>(Click over to mark as done)</em></p>
        <ol id="todo"></ol>
      </div>
    
      <div id="right">
        <h1>Done:</h1>
        <p class="instruction"><em>(Click over to delete it)</em></p>
        <p id="placeholder"></p>
        <ol id="done"></ol>
      </div>
    </div>