0

I need help with deleting an object from the array.

The names(array.name) from the objects are displayed in the DOM and I want to delete them using the erase X button .

In this code I can only delete one element and then stops working with no console error. Does anyone have an idea where I am wrong and why I can't call the create() function every time I click on an erase button.

Look at console.log... it shows the good position and name of the element to be deleted, but everything stops when I call create() function, try uncomment create().

const array = [ {name: 'John'}, {name: 'David'}, {name: 'Peter'}, {name: 'Michael'} ]; 

const create = () => {
    const app = document.querySelector('.app');
    app.innerHTML = '';

    for(let i = 0; i < array.length; i++) {
      app.innerHTML += `<div class="item"><span class="erase">&#9747;</span>${array[i].name}</div>`;
    }
}
create();

const erase = document.querySelectorAll('.erase');

erase.forEach(item => {
    item.onclick = () => {
      const itemText = item.parentElement.textContent.substr(1);
      const itemPos = array.findIndex(item => item.name == itemText);
    
        console.log(itemText + ' ' + itemPos);
        console.log(array);
        array.splice(itemPos, 1);
        //create()
    }
});
.erase {
  color: red;
  margin-right: 20px;
  cursor: pointer;
}

.item {
  margin-bottom: 10px;
}
<div class="app"></div>

Or as fiddle: https://jsfiddle.net/05cwy9d2/3/

6 Answers 6

3

Its because when you create new elements in the dom the listeners of old elements are being removed together with the old elements. Just move the event listener registration into create method.

const array = [
  {name: 'John'},
  {name: 'David'},
  {name: 'Peter'},
  {name: 'Michael'}
]; 

const create = () => {
  const app = document.querySelector('.app');
  app.innerHTML = '';

  for(let i=0;i<array.length;i++){
    app.innerHTML += 
      `<div class="item"><span class="erase">&#9747;</span>${array[i].name}</div>`;
  }

  const erase = document.querySelectorAll('.erase');

  erase.forEach(item => {
    item.onclick = () => {
      const itemText = item.parentElement.textContent.substr(1);
      const itemPos = array.findIndex(item => item.name == itemText);


      console.log(itemText + ' ' + itemPos);
      console.log(array);
      array.splice(itemPos, 1);
      create();
    }
  });
}

create();
.erase{
color: red;
margin-right: 20px;
cursor: pointer;
}
.item{
margin-bottom: 10px;
}
<div class="app"></div>

Sign up to request clarification or add additional context in comments.

Comments

1
const array = [
  {name: 'John'},
  {name: 'David'},
  {name: 'Peter'},
  {name: 'Michael'}
]; 

const create = () => {
    const app = document.querySelector('.app');
    app.innerHTML = '';

    for(let i=0;i<array.length;i++){
      app.innerHTML += 
      `<div class="item"><span class="erase">&#9747;</span>${array[i].name}</div>`;
    }
}
create();

const erase = document.querySelectorAll('.erase');

erase.forEach(item => {

    item.onclick = () => {
      const itemText = item.parentElement.textContent.substr(1);
      const itemPos = array.findIndex(item => item.name == itemText);
    
        console.log(itemText + ' ' + itemPos);
        
        if(itemPos >-1){
            array.splice(itemPos, 1);
            item.parentElement.remove();
        }
        console.log(array);
    }
});

This works now. I have removed DOM when clicked on erase and disabled user to delete an element that has already been deleted (if index == -1).

1 Comment

This sounds a good solution, you dont have to re render the whole array when one element is deleted, you just remove the clicked element from the dom, and actually check for index here is redundant I think, becuase user will never click on not existing element as it will be removed when clicked anyways. But only if the array should be synchronised with the dom.
0

You need to just remove the dom element

    e.target.parentNode.parentNode.removeChild(e.target.parentNode);

https://jsfiddle.net/tLk5vmy0/

Comments

0

You can use the method removeChild to remove the element from your DOM, this way will prevent to re-render (with create method) every time you remove an item from the array. This way, your code will need some changes, the first of these is to have an id for each element of your array:

for(let person of array){
  app.innerHTML += 
  `<div class="item" id="${person.name}"><span class="erase">&#9747;</span>${person.name}</div>`;
}

After having the "person" name as your id (I recommend that you have a real identifier, like a number, but for this example the name will help us) , you can only remove that node from DOM:

const elementToRemove = document.getElementById(item.parentElement.id);
elementToRemove.parentNode.removeChild(elementToRemove);

To enhance, you can check if the node exists, and if not you can throw an error to your console:

const elementToRemove = document.getElementById(item.parentElement.id);

if (!elementToRemove) throw new Error(`Element ${item.parentElement.id} not found!`)

elementToRemove.parentNode.removeChild(elementToRemove)

I recommend that you read the Node section on MDN this can be useful to add other elements to the list, edit some elements, and more. :)

Comments

0

I moved the eventlistener code to the create function because the need to get recreated when one event occured. You could also use the EventTarget.addEventListener() method to bind eventlisteners to every single DOM-element.

I would also prefer to use the Array.prototype.filter() method to remove the clicked value for better readability:

let array = [
  {name: 'John'},
  {name: 'David'},
  {name: 'Peter'},
  {name: 'Michael'}
]; 

const addEventListeners = () => {
  const erase = document.querySelectorAll('.erase');
  erase.forEach(item => {
    item.onclick = (e) => {
        const itemText = item.parentElement.textContent.substr(1);
        array = array.filter(entry => entry.name !== itemText);
        create();
    }
  });
}

const create = () => {
    const app = document.querySelector('.app');
    app.innerHTML = '';

    for(let i=0;i<array.length;i++){
      app.innerHTML += 
      `<div class="item"><span class="erase">&#9747;</span>${array[i].name}</div>`;
    }
    addEventListeners();
}
create();
<div class="app"></div>

Comments

0

instead of calling create() function again and creating new child elements for class '.app' you would use item.parentElement.remove(); in place of create() in onClick. That would have same result.

erase.forEach(item => {

item.onclick = () => {
 console.log()
  const itemText = item.parentElement.textContent.substr(1);
  const itemPos = array.findIndex(item => item.name == itemText);

    console.log(itemText + ' ' + itemPos);
    console.log(array);
    array.splice(itemPos, 1);
   item.parentElement.remove(); // this will remove your element.
  // create();
  
}

});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.