skip to Main Content

I have the following function for iterating through an array of activities and displaying them. The function also includes a trash-icon that is meant to clear away any specific item that is selected by clicking:

const renderList = (activities) => {
  const display = document.getElementById('task-list-display');
  activities.forEach((activity) => {
    display.insertAdjacentHTML('beforeend', ` 
    <li id="task-item" class="task-item">
      <div class="chk-descr">
        <input 
          data-a1="${activity.index}"
          type="checkbox"
          name="completed"
          class="completed"
          />
        <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
      </div>
        <i class="clear-item fa fa-trash"/></i>
    </li> 
    `);
    const listItem = document.querySelectorAll('.task-item')[0];
    const clearItem = document.querySelectorAll('.clear-item')[0];
    clearItem.addEventListener('click', () => {
      display.removeChild(listItem);
    });
  });
};

The display is working perfectly. However, I am having no success in clearing the items. No success, that is, unless the item selected is the one at the very top of the list. In that case, the item is removed from display, but I obtain the following error:

Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

When clicking on the items below that one, there is no response at all.

I understand that this has to do with using insertAdjacentHTML to insert the items into display but I do not know what I can use in its stead. remove(listItem) also does not work.

Thanks in advance to anyone that can enlighten me in regards to this matter.

4

Answers


  1. When you insert the item at the end, it will be the last element in the list returned by querySelectorAll(), not the first. So use

        const allTasks = document.querySelectorAll('.task-item');
        const listItem = allTasks[allTasks.length-1];
        const clearItem = listItem.querySelector('.clear-item');
    
    Login or Signup to reply.
  2. Just replace it with this code :

    clearItem.addEventListener('click', () => {
          display.removeChild(display.firstElementChild);
        });
    

    cause you are not telling the removeChild() the target child correctly

    Login or Signup to reply.
  3. Instead of adding the click handler every time you add the item, you can delegate it to the document.body just once. Then look for the class on the item clicked, and if it matches your delete button remove that button’s parent node.

    const renderList = (activities) => {
      const display = document.getElementById('task-list-display');
      activities.forEach((activity) => {
        display.insertAdjacentHTML('beforeend', ` 
        <li id="task-item" class="task-item">
          <div class="chk-descr">
            <input 
              data-a1="${activity.index}"
              type="checkbox"
              name="completed"
              class="completed"
              />
            <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
          </div>
            <i class="clear-item fa fa-trash"/>DELETE</i>
        </li> 
        `);
      });
    };
    
    renderList([
      {"index": "0","description" : "test","title" :"tests" },
      {"index": "30","description" : "xtest","title" :"testsX" }
    ]);
    
    document.body.addEventListener("click",(e) => {
      let el = e.target;
      if(el.classList.contains("clear-item")){
        el.parentNode.remove();
      }
    });
    <div id='task-list-display'></div>
    Login or Signup to reply.
  4. The code const listItem = document.querySelectorAll('.task-item')[0]; can return another item which is not child of display.

    You can set different id for each list Item and clear Item. Like this.

    const renderList = (activities) => {
      const display = document.getElementById('task-list-display');
      activities.forEach((activity) => {
        display.insertAdjacentHTML('beforeend', ` 
        <li id="task-item-${activity.index}" class="task-item">
          <div class="chk-descr">
            <input 
              data-a1="${activity.index}"
              type="checkbox"
              name="completed"
              class="completed"
              />
            <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
          </div>
            <i id="clear-item-${activity.index}" class="clear-item fa fa-trash"/></i>
        </li> 
        `);
        const listItem = document.getElementById('task-item-'+${activity.index});
        const clearItem = document.getElementById('clear-item-'+${activity.index});
        clearItem.addEventListener('click', () => {
          display.removeChild(listItem);
        });
      });
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search