user15987286
user15987286

Reputation:

Trying to create a button with an li and it's not working

I'm trying to make a grocery list app using an array similar to a todo list. I've got it working with an add button, and had a remove button that would remove an item from the list. But now I'm trying to make it so that a remove button is created with each li so that each grocery item can be selectively removed. I gave it a shot but I'm not quite sure what I've done wrong here.

let addButton = document.getElementById('add-button');
addButton.addEventListener('click', add);

let addInput = document.getElementById('add-input');

//let removeButton = document.getElementById('remove-button');
//removeButton.addEventListener('click', remove);

let groceryList = [

]

function add() {
  groceryInput = addInput.value;
  groceryList.push(groceryInput);
  addInput.value = '';
  displayGroceries();
}

function remove(event) {
  let position = event.currentTarget.id;
  groceryList.splice(position, 1);
  displayGroceries();
}

function displayGroceries() {
  let groceryUl = document.getElementById('grocery-ul');
  groceryUl.innerHTML = '';

  for (let i = 0; i < groceryList.length; i++) {
    let groceryLi = document.createElement('li');
    groceryLi.innerHTML = groceryList[i];
    groceryUl.appendChild(groceryLi);

  }

  let removeButton = document.createElement('button');
  removeButton.innerText = "Remove";
  removeButton.addEventListener('click', remove);
  removeButton.id = i;
  groceryLi.appendChild(removeButton);

}
<div class="container">
  <h1>Grocery List</h1>
  <input id="add-input" placeholder="Add Groceries" autocomplete="off">
  <button id="add-button">Add</button>
  <!--<button id="remove-button">Remove</button>-->
  <div>
    <ul id="grocery-ul"></ul>
  </div>

Upvotes: 0

Views: 70

Answers (2)

dale landry
dale landry

Reputation: 8600

In your example you are calling on the incrementing value of i outside of the scope of its loop.

You can create the button using the same method you are using to create your list item tag, then add the button to the UL element tag using .insertAdjacentElement('beforeend', removeBtn).

Then you can use a removeEl function that looks at the event.target parentNode and firstChild --> li that will contain the grocery item and its remove button to both remove the element from the DOM and the array.

function removeEl(event) {
  event.target.parentNode.remove(event.target)
  if (groceryList.includes(event.target.parentNode.firstChild.textContent)) {
    let k = groceryList.indexOf(event.target.parentNode.firstChild.textContent);
    if (k !== -1) {
      groceryList.splice(k, 1);
    }
  }
  displayGroceries();
}

//and the for loop that creates the new elements in displayGroceries()

for (let i = 0; i < groceryList.length; i++) {
    let groceryLi = document.createElement('LI');
    let removeBtn = document.createElement('BUTTON');
    groceryUl.classList.add('flex-display')
    removeBtn.textContent = `remove ${groceryList[i]}`;
    removeBtn.setAttribute('onclick', `removeEl(event)`)
    groceryLi.innerHTML = groceryList[i];
    groceryUl.appendChild(groceryLi);
    groceryLi.insertAdjacentElement('beforeend', removeBtn);
  } 

let addButton = document.getElementById('add-button');
addButton.addEventListener('click', add);

let addInput = document.getElementById('add-input');

//let removeButton = document.getElementById('remove-button');
//removeButton.addEventListener('click', remove);

let groceryList = [

]

function add() {
  groceryInput = addInput.value;
  groceryList.push(groceryInput);
  addInput.value = '';
  displayGroceries();
}

function removeEl(event) {
  //this targets the LI element, parent of the button
  event.target.parentNode.remove(event.target)
  //event.target.parentNode.firstChild.textContent -> the grocery item
  if (groceryList.includes(event.target.parentNode.firstChild.textContent)) {
    // get the index 
    let k = groceryList.indexOf(event.target.parentNode.firstChild.textContent);
    if (k !== -1) {
      groceryList.splice(k, 1);
    }
  }
  displayGroceries();
}

function displayGroceries() {
  let groceryUl = document.getElementById('grocery-ul');
  groceryUl.innerHTML = '';

  for (let i = 0; i < groceryList.length; i++) {
    let groceryLi = document.createElement('LI');
    let removeBtn = document.createElement('BUTTON');
    groceryUl.classList.add('flex-display')
    removeBtn.textContent = `remove ${groceryList[i]}`;
    removeBtn.setAttribute('onclick', `removeEl(event)`)
    groceryLi.innerHTML = groceryList[i];
    groceryUl.appendChild(groceryLi);
    groceryLi.insertAdjacentElement('beforeend', removeBtn);
  }
}
.flex-display {
  display: flex;
  align-items: start;
  flex-direction: column;
}

li {
  list-style: none;
}

button {
  margin-left: 1rem;
}
<div class="container">
  <h1>Grocery List</h1>
  <input id="add-input" placeholder="Add Groceries" autocomplete="off">
  <button id="add-button">Add</button>
  <!--<button id="remove-button">Remove</button>-->
  <div>
    <ul id="grocery-ul">

    </ul>
  </div>

Upvotes: 0

Harshit
Harshit

Reputation: 157

Its not working as groceryLi.appendChild(removeButton) you are calling outside for loop.

You have defined groceryLi using let and let have a block scope.

Moving code to add button inside resolves issue

Find fixed method for displayGroceries as follows

function displayGroceries() {
  let groceryUl = document.getElementById('grocery-ul');
  groceryUl.innerHTML = "";
  for (let i = 0; i < groceryList.length; i++) {
    let groceryLi = document.createElement("li");
    groceryLi.innerHTML = groceryList[i];
    let removeButton = document.createElement("button");
    removeButton.innerText = "Remove";
    removeButton.addEventListener("click", remove);
    removeButton.id = i;
    groceryLi.appendChild(removeButton);
    groceryUl.appendChild(groceryLi);
  }
}

Upvotes: 1

Related Questions