5

I am trying to push a ingredient to a list of array. This ingredient is an object and has its id from uuid or any library and an ingredient value of whatever the user types on the input.

I wrote the simplest example of it in a single function so its clear to understand the core of my doubt.

How can I delete the item by id and re-render, if the button is part of the renderization.

I could create a render function and invoke it inside the remove button. The problem is that the button would be part of that function.

Code

let ingredients = []

document.querySelector('#ingredients-input').addEventListener('change', (e) => {
  e.preventDefault()

  const id = uuid()

  ingredients.push({
    id: id,
    title: e.target.value
  })

  const ingredientUl = document.createElement('p')
  const removeButton = document.createElement('button')

  ingredientUl.textContent = e.target.value
  removeButton.textContent = 'remove'

  document.querySelector('#ingredients').append(ingredientUl, removeButton)

  removeButton.addEventListener('click', (e) => {
    const ingredientIndex = ingredients.findIndex(el => el.id === id)
    ingredients.splice(ingredientIndex, 1)
  })
})
<div id="ingredients"></div>
<input id="ingredients-input">

CodePen: https://codepen.io/notnishi/pen/QWyPdLL

Any help would be appreciated.

0

3 Answers 3

3

Instead of re rendering, you can delete the p tag and the remove button from#ingredients. Deleting only the specific elements from DOM is much more efficient than rerendering the whole ingredients list for just one change.

The remove button can be removed by using ChildNode.remove() and for deleting the ingredientUl, we can iterate over the child list of #ingredients and find the item to removed first and then delete it using Node.removeChild()

let ingredients = [];
const ingredientsNodeList = document.querySelector("#ingredients");

document.querySelector("#ingredients-input").addEventListener("change", (e) => {
  e.preventDefault();

  const id = uuid();

  ingredients.push({
    id: id,
    title: e.target.value,
  });

  const ingredientUl = document.createElement("p");
  const removeButton = document.createElement("button");

  ingredientUl.textContent = e.target.value;
  ingredientUl.id = id;
  e.target.value = ""; // Clearing the input after entering it to ingredients list
  removeButton.textContent = "remove";

  ingredientsNodeList.append(ingredientUl, removeButton);

  removeButton.addEventListener("click", (e) => {
    const ingredientIndex = ingredients.findIndex((el) => el.id === id);
    ingredients.splice(ingredientIndex, 1);

    const itemToDelete = [...ingredientsNodeList.children].find(el => el.id === id);
    ingredientsNodeList.removeChild(itemToDelete); // Removing ingredientUl
    e.target.remove(); // Deleting removeButton
  });
});
Sign up to request clarification or add additional context in comments.

Comments

1

Similar solution to one of the previous answer, but I would wrap your added items in a div with an attribute that holds the value of your uuid, so you can easily find the uuid when click the remove button and then you can manually update the values in your ingredients array and also manually remove the wrapping div from the DOM.

CodePen demo

let ingredients = []

document.querySelector('#ingredients-input').addEventListener('change', (e) => {
  e.preventDefault()
  
  const id = uuid()
  
  ingredients.push({ 
    id: id,
    title: e.target.value
  })
  
  const wrapper = document.createElement('div')
  wrapper.setAttribute('data-uuid', id)
  const ingredientUl = document.createElement('p')
  const removeButton = document.createElement('button')
  
  ingredientUl.textContent = e.target.value
  removeButton.textContent = 'remove'
  
  wrapper.append(ingredientUl, removeButton)
  
  document.querySelector('#ingredients').append(wrapper)
  
  removeButton.addEventListener('click', (e) => {
    const wrapper = e.target.closest('div[data-uuid]');
    const wrapperUuid = wrapper.getAttribute('data-uuid');
    // Filters out the ingredient associated with the clicked remove button
    ingredients = ingredients.filter(ingredient => ingredient.id !== wrapperUuid)
    // Removes element from dom
    wrapper.remove()
  })
})

Comments

1

let ingredients = [];
function remove(evt,id){
  const ingredientIndex = ingredients.findIndex((el) => el.id === id);
    ingredients.splice(ingredientIndex,1);
  renderElem();
  renderElem();
};
function renderElem() {
  document.querySelector("#ingredients").innerHTML='';
  ingredients.forEach((emp) => {
    const ingredientUl = document.createElement("p");
    const removeButton = document.createElement("button");
    ingredientUl.textContent = emp.title;
    removeButton.textContent = "remove";
removeButton.addEventListener("click", (e) => {
  remove(e,emp.id);  
});
  document.querySelector("#ingredients").append(ingredientUl, removeButton);
  });
}
document.querySelector("#ingredients-input").addEventListener("change", (e) => {
  e.preventDefault();
  const id = uuid();
  ingredients.push({
    id: id,
    title: e.target.value
  });
  renderElem();
});
* {
  background: black;
  color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/node-uuid/1.4.8/uuid.min.js"></script>
  <body>
    <div id="ingredients"></div>
    <input id="ingredients-input">
  </body>

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.