I'm making a simple task list that will take user input and append it to and unordered list whenever the add button is clicked. Once the item is added the text will be appended to a list element along with a delete button. I'm new to JavaScript so I don't quite know how to make the delete button remove the list element that the user clicks on. Note: it's a span element, not a button.
I think removeChild() might be good, but I can't seem to implement it.
let addButton = document.getElementById("add-item");
addButton.addEventListener("click", function () {
// Retrieves the 'list'
let list = document.getElementById("items");
let textNode = window.prompt("Enter item:");
if (textNode != null) {
let item = document.createElement("li");
//Creates a textnode from the users input
item.appendChild(document.createTextNode(textNode));
//Adds the users textnode at the end of the list
list.appendChild(item);
// Creates a delete button
let deleteButton = document.createElement("span");
deleteButton.innerHTML = "Delete"
item.appendChild(deleteButton)
}
});
ul {
padding: 0px;
}
li {
display: flex;
background-color: #eee;
margin: 5px;
padding: 5px;
align-items: center;
}
li > span {
margin-left: auto;
background-color: #aaa;
padding: 5px;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="app_2.css" rel="stylesheet">
<title>Items</title>
</head>
<body>
<h1>Items</h1>
<ul id="items">
<!--
This is the template for an item in the list:
<li>The first item is free! <span>Delete</span></li>
-->
</ul>
<button type="button" id="add-item">Add item</button>
<script src="app_2.js"></script>
</body>
</html>
CodePudding user response:
You can add a click event on deleteButton
to handle that case
deleteButton.addEventListener("click", function() {
item.remove()
})
Full code
let addButton = document.getElementById("add-item");
const currentIndex = 0
addButton.addEventListener("click", function() {
// Retrieves the 'list'
let list = document.getElementById("items");
let textNode = window.prompt("Enter item:");
if (textNode != null) {
let item = document.createElement("li");
//Creates a textnode from the users input
item.appendChild(document.createTextNode(textNode));
//Adds the users textnode at the end of the list
list.appendChild(item);
// Creates a delete button
let deleteButton = document.createElement("span");
//add a click event to remove the current item
deleteButton.addEventListener("click", function() {
item.remove()
})
deleteButton.innerHTML = "Delete"
item.appendChild(deleteButton)
}
});
ul {
padding: 0px;
}
li {
display: flex;
background-color: #eee;
margin: 5px;
padding: 5px;
align-items: center;
}
li>span {
margin-left: auto;
background-color: #aaa;
padding: 5px;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="app_2.css" rel="stylesheet">
<title>Items</title>
</head>
<body>
<h1>Items</h1>
<ul id="items">
<!--
This is the template for an item in the list:
<li>The first item is free! <span>Delete</span></li>
-->
</ul>
<button type="button" id="add-item">Add item</button>
<script src="app_2.js"></script>
</body>
</html>
CodePudding user response:
Here is how you can add an event listener to the delete button and make the delete button remove the item from the list. I have added comments in the code to show where I made changes and explain whats going on.
let addButton = document.getElementById("add-item");
addButton.addEventListener("click", function () {
// Retrieves the 'list'
let list = document.getElementById("items");
let textNode = window.prompt("Enter item:");
if (textNode != null) {
let item = document.createElement("li");
//Creates a textnode from the users input
item.appendChild(document.createTextNode(textNode));
//Adds the users textnode at the end of the list
list.appendChild(item);
// Creates a delete button
let deleteButton = document.createElement("span");
deleteButton.innerHTML = "Delete"
item.appendChild(deleteButton);
//add an event listener for the delete button
deleteButton.addEventListener("click", function(){
//get the parent of the span (li)
let listItem = this.parentNode;
//get the parent of the list item (ul)
let list = listItem.parentNode;
//remove the child from the list
list.removeChild(listItem);
});
}
});
ul {
padding: 0px;
}
li {
display: flex;
background-color: #eee;
margin: 5px;
padding: 5px;
align-items: center;
}
li > span {
margin-left: auto;
background-color: #aaa;
padding: 5px;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="app_2.css" rel="stylesheet">
<title>Items</title>
</head>
<body>
<h1>Items</h1>
<ul id="items">
<!--
This is the template for an item in the list:
<li>The first item is free! <span>Delete</span></li>
-->
</ul>
<button type="button" id="add-item">Add item</button>
<script src="app_2.js"></script>
</body>
</html>
CodePudding user response:
Use event delegation. Instead of attaching listeners to every button add one listener to the parent element (in this case the ul
element), and have that capture all the events from its child elements as they "bubble up" the DOM, and have that listener call a function to update the list.
I've used a slightly more modern approach to building the rows in my answer that you may find useful. Links to all the relevant MDN documentation are at the end of the answer.
const items = document.querySelector('#items');
const addButton = document.querySelector('#add-item');
// Add listeners to both button and the items list element
// In the case of `addItem` you can see that I'm calling the
// function instead of returning a function reference. This will
// become relevant later. `addClick` returns a _new_ function that
// will be used as the listener
items.addEventListener('click', handleClick, false);
addButton.addEventListener('click', addItem(), false);
function handleClick(e) {
// Because we're using event delegation we need
// to check that the element we clicked on was
// the button with the delete class
if (e.target.matches('.delete')) {
// If it is destructure the id from
// the element's dataset
const { id } = e.target.dataset;
// Use that to build a selector
const selector = `li[data-id="${id}"]`;
// And remove that list item from the list
items.querySelector(selector).remove();
}
}
// Because I want as few global variables as possible
// I'm using a closure. Basically a function that retains
// it's outer lexical environment when it's returned.
// The inner function is the function that's used as the
// handler for the listener but it retains a copy of `id`
// which it can update when called
function addItem() {
let id = 0;
return function () {
const text = window.prompt('Enter item:');
if (text) {
// Instead of `createElement` I'm using a template
// string to build the HTML. Add the id to both the
// item and the button so that when the button is
// clicked the handleClick function can
// remove the right item
const html = `
<li data-id="${id}">
${text}
<button
type="button"
data-id="${id}"
>Delete
</button>
</li>
`;
// That HTML gets added to the list
items.insertAdjacentHTML('beforeend', html);
// And the row id is increased
id;
}
}
}
ul{padding:0}
li{display:flex;background-color:#eee;margin:5px;padding:5px;align-items:center}
.delete{margin-left:auto;background-color:#aaa;padding:5px;cursor:pointer}
<h1>Items</h1>
<ul id="items"></ul>
<button type="button" id="add-item">Add item</button>
Additional documentation