Reputation:
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
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
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