最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - JS delete specific <li> element by addEventListener() - Stack Overflow

programmeradmin0浏览0评论

I am a newbie in JS and DOM.

I'd like to delete a specific li item by clicking on its child delete button by using addEventListener(). I have found a few relevant solutions like this one, but I'm trying to e up with a more elegant solution.

<ul>
    <li>Notebook</li>
    <li>Jello</li>
    <li>Spinach</li>
    <li>Rice</li>
    <li>Birthday Cake</li>
    <li>Candles</li>
</ul>

The following is a snipped JavaScript code I have tested but not had success with.

function removeItem(e) {
    e.target.parentNode.remove();
}

deleteButton.addEventListener("click", removeItem);

Here is the full code:

var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var deleteButton = document.createElement("button");

Array.from(ul.children).forEach( function(item) {
	appendDeleteBtnTo(item);
})

function appendDeleteBtnTo(element) {
	var deleteButton = document.createElement("button");
	deleteButton.innerHTML = "Delete";
	deleteButton.classList.add("delete");
	element.appendChild(deleteButton);
}

function lineThrough(e) {
	if (e.target.tagName === "LI") {
		e.target.classList.toggle("done");
	}
}

// =========== not working ====================================
function removeItem(e) {
	e.target.parentNode.parentNode.remove();
}

deleteButton.addEventListener("click", removeItem);
// =============================================================

function inputLength() {
	return input.value.length;
}

function createListElement() {
	var li = document.createElement("li");
	li.appendChild(document.createTextNode(input.value));
	ul.appendChild(li);
	input.value = "";
	appendDeleteBtnTo(li);
}

function addListAfterClick() {
	if (inputLength() > 0) {
		createListElement();
	}
}

function addListAfterKeypress(event) {
	if (inputLength() > 0 && event.keyCode === 13) {
		createListElement();
	}
}


ul.addEventListener("click", lineThrough);
button.addEventListener("click", addListAfterClick);
input.addEventListener("keypress", addListAfterKeypress);
.done {
  text-decoration: line-through;
}

ul li:hover {
  background-color: rgba(0, 0, 0, 0.05);
}
<!DOCTYPE html>
<html>
<head>
	<title>Javascript + DOM</title>
	<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
	<h1>Shopping List</h1>
	<p id="first">Get it done today</p>
	<input id="userinput" type="text" placeholder="enter items">
	<button id="enter">Enter</button>
	<ul>
		<li class="bold red" random="23">Notebook</li>
		<li>Jello</li>
		<li>Spinach</li>
		<li>Rice</li>
		<li>Birthday Cake</li>
		<li>Candles</li>
	</ul>
	<script type="text/javascript" src="script.js"></script>
</body>
</html>

I am a newbie in JS and DOM.

I'd like to delete a specific li item by clicking on its child delete button by using addEventListener(). I have found a few relevant solutions like this one, but I'm trying to e up with a more elegant solution.

<ul>
    <li>Notebook</li>
    <li>Jello</li>
    <li>Spinach</li>
    <li>Rice</li>
    <li>Birthday Cake</li>
    <li>Candles</li>
</ul>

The following is a snipped JavaScript code I have tested but not had success with.

function removeItem(e) {
    e.target.parentNode.remove();
}

deleteButton.addEventListener("click", removeItem);

Here is the full code:

var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var deleteButton = document.createElement("button");

Array.from(ul.children).forEach( function(item) {
	appendDeleteBtnTo(item);
})

function appendDeleteBtnTo(element) {
	var deleteButton = document.createElement("button");
	deleteButton.innerHTML = "Delete";
	deleteButton.classList.add("delete");
	element.appendChild(deleteButton);
}

function lineThrough(e) {
	if (e.target.tagName === "LI") {
		e.target.classList.toggle("done");
	}
}

// =========== not working ====================================
function removeItem(e) {
	e.target.parentNode.parentNode.remove();
}

deleteButton.addEventListener("click", removeItem);
// =============================================================

function inputLength() {
	return input.value.length;
}

function createListElement() {
	var li = document.createElement("li");
	li.appendChild(document.createTextNode(input.value));
	ul.appendChild(li);
	input.value = "";
	appendDeleteBtnTo(li);
}

function addListAfterClick() {
	if (inputLength() > 0) {
		createListElement();
	}
}

function addListAfterKeypress(event) {
	if (inputLength() > 0 && event.keyCode === 13) {
		createListElement();
	}
}


ul.addEventListener("click", lineThrough);
button.addEventListener("click", addListAfterClick);
input.addEventListener("keypress", addListAfterKeypress);
.done {
  text-decoration: line-through;
}

ul li:hover {
  background-color: rgba(0, 0, 0, 0.05);
}
<!DOCTYPE html>
<html>
<head>
	<title>Javascript + DOM</title>
	<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
	<h1>Shopping List</h1>
	<p id="first">Get it done today</p>
	<input id="userinput" type="text" placeholder="enter items">
	<button id="enter">Enter</button>
	<ul>
		<li class="bold red" random="23">Notebook</li>
		<li>Jello</li>
		<li>Spinach</li>
		<li>Rice</li>
		<li>Birthday Cake</li>
		<li>Candles</li>
	</ul>
	<script type="text/javascript" src="script.js"></script>
</body>
</html>

Share Improve this question edited Jan 24, 2020 at 19:14 zima asked Jan 24, 2020 at 18:14 zimazima 211 silver badge7 bronze badges 4
  • 2 You really should put the code in the question. Stackoverflow has the same snipplets which is the same functionality. – epascarello Commented Jan 24, 2020 at 18:18
  • 1 Problem is deleteButton you create is not the same as you add event listener too.... SHould be adding event when you create each button. – epascarello Commented Jan 24, 2020 at 18:19
  • The code included in the question does not provide a minimal reproducible example. Please edit your question to include all relevant code to show where you are having a problem. You can use Stack Snippets to provide a runnable example here on SO. – Heretic Monkey Commented Jan 24, 2020 at 18:38
  • I appreciate all of you for your advice – zima Commented Jan 24, 2020 at 19:16
Add a ment  | 

5 Answers 5

Reset to default 3

Use event delegation by setting the event handler on the parent, and checking who is the actual target in the handler. This has two advantages:

  1. You can add/remove list items without the need to attach event handlers to the added item.
  2. You can easily bine the delete and line through functionalities in a single simple handler.

The event handler is added to the list (ul). Whenever the list or its children are click, the handler checks if the target is/inside a list item use Element.closest(). If no list item is found in the chain, the function terminates (return). If a list item is found (target), we check if the actual click target was the delete button. If it's the delete button the target is removed. If not, the the done class is added.

function listItemClickHandler(e) {
  const li = e.target.closest('li');

  if(!li) return;

  if (e.target.matches('.delete')) {
    li.remove();
  } else {
    li.classList.toggle('done');
  }    
}

var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var deleteButton = document.createElement("button");

Array.from(ul.children).forEach(function(item) {
  appendDeleteBtnTo(item);
})

function appendDeleteBtnTo(element) {
  var deleteButton = document.createElement("button");
  deleteButton.innerHTML = "Delete";
  deleteButton.classList.add("delete");
  element.appendChild(deleteButton);
}

function inputLength() {
  return input.value.length;
}

function createListElement() {
  var li = document.createElement("li");
  li.appendChild(document.createTextNode(input.value));
  ul.appendChild(li);
  input.value = "";
  appendDeleteBtnTo(li);
}

function addListAfterClick() {
  if (inputLength() > 0) {
    createListElement();
  }
}

function addListAfterKeypress(event) {
  if (inputLength() > 0 && event.keyCode === 13) {
    createListElement();
  }
}

function listItemClickHandler(e) {
  const li = e.target.closest('li');
  
  if(!li) return;
  
  if (e.target.matches('.delete')) {
    li.remove();
  } else {
    li.classList.toggle('done');
  }    
}

ul.addEventListener("click", listItemClickHandler);
button.addEventListener("click", addListAfterClick);
input.addEventListener("keypress", addListAfterKeypress);
.done {
  text-decoration: line-through;
}

ul li:hover {
  background-color: rgba(0, 0, 0, 0.05);
}
<h1>Shopping List</h1>
<p id="first">Get it done today</p>
<input id="userinput" type="text" placeholder="enter items">
<button id="enter">Enter</button>
<ul>
  <li class="bold red" random="23">Notebook</li>
  <li>Jello</li>
  <li>Spinach</li>
  <li>Rice</li>
  <li>Birthday Cake</li>
  <li>Candles</li>
</ul>

From your demo (truncated):

var deleteButton = document.createElement("button"); //<-- never inserted into DOM
//...
function appendDeleteBtnTo(element) {
    var deleteButton = document.createElement("button");
    deleteButton.innerHTML = "Delete";
    deleteButton.classList.add("delete");
    element.appendChild(deleteButton);
}
deleteButton.addEventListener("click", removeItem);

The problem is the deletion button you're assigning the event to is not the same as the deletion button you're ultimately appending to each li - that's being done quite separately inside appendDeleteBtnTo(). In fact, the one you're binding to is never actually inserted into the DOM.

You could bind the event inside that same function. Better, and more economical, would be to bind the event to the body (or at least some container) and thus 'delegate' the event, checking when it fires whether it applies to your specific circumstance.

We do that by checking what populated the target property of the event object.

document.body.addEventListener('click', evt => {
    if (!evt.target.matches('li > button')) return; //quit - click was not to li > button
    removeItem(evt); //remove li
});

I'm trying to e up with a more elegant solution

Since your callback is neither long nor elaborate, you can - rather than calling a named function - add an anonymous callback to your .addEventListener() method which contains the ES2015 .remove():

.addEventListener('click', (e) => e.target.parentNode.remove(), false)

Working Example:

const shoppingList = document.getElementsByTagName('ul')[0];
const shoppingListItems = [... shoppingList.getElementsByTagName('li')];

for (shoppingListItem of shoppingListItems) {

  let deleteButton = document.createElement('button');
  deleteButton.type = 'button';
  deleteButton.classList.add('deleteButton');
  deleteButton.textContent = 'Delete this';
  deleteButton.addEventListener('click', (e) => e.target.parentNode.remove(), false);
  shoppingListItem.appendChild(deleteButton);
}
li {
  padding: 6px 0;
  font-size: 16px;
  line-height: 24px;
}

.deleteButton {
  display: inline-block;
  margin-left: 12px;
}
<ul>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>

Here We want to attach the event listener to each of the delete buttons that are being created. See the modified fiddle.

function appendDeleteBtnTo(element) {
    var deleteButton = document.createElement("button");
    deleteButton.innerHTML = "Delete";
    deleteButton.classList.add("delete");
    element.appendChild(deleteButton);

    deleteButton.addEventListener("click", removeItem);
}
Add Event Listener to each delete button where they have created.

function appendDeleteBtnTo(element) {
    var deleteButton = document.createElement("button");
    deleteButton.innerHTML = "Delete";
    deleteButton.classList.add("delete");
    deleteButton.addEventListener("click", removeItem); // add the event lisntener
    element.appendChild(deleteButton);
}

function removeItem(e) {
    e.target.parentNode.remove();
}

See the edited jsFiddle

发布评论

评论列表(0)

  1. 暂无评论