首页 > 解决方案 > How can I get my JavaScript delete function to fire more than once?

问题描述

I'm building a todo app and I use a function to create a list item entered by the user.

There is an event listener added to the output section to listen for a delete button click for each item displayed. My problem is that the delete button is only working for one item and then it stops working.

In the console, it appears that the function is actually called every time I press the button, but the functionality only works for one click. Do I need to add all the list items into an array perhaps?

const todo = document.getElementById('todo');
const enter = document.getElementById('enter');
const output = document.getElementById('output');
enter.addEventListener('click', () => {
  listItem(todo);
});
let createListItem;
var deleteBtn;
let checkBtn;

function listItem(todo) {
  createListItem = document.createElement('li');
  createListItem.innerText = todo.value;
  todo.value = '';

  output.appendChild(createListItem);

  checkBtn = document.createElement('button');
  deleteBtn = document.createElement('button');

  checkBtn.innerText = 'check';
  deleteBtn.innerText = 'delete';

  createListItem.append(checkBtn);
  createListItem.append(deleteBtn);

  checkBtn.classList.add('checkBtn');
  deleteBtn.classList.add('deleteBtn');

}
output.addEventListener('click', deleteFunc);

function deleteFunc() {
  console.log('function called');
  createListItem.remove();
}
<section class="controls">
  <div>
    <label for="todo">Enter a to-do</label>
    <input type="text" name="todo" id="todo">
  </div>
  <span>
    <button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button>
  </span>
</section>
<section>
  <ul id="output" class="output">

  </ul>

</section>

标签: javascript

解决方案


You need to delegate and use relative addressing because your code only removes the LAST added LI

The variable createListItem pollutes the global scope. Add the keyword var or let in the listItem function too

function deleteFunc(e) {
  console.log('function called');
  const tgt = e.target;
  if (e.target.innerText==="delete") tgt.closest("li").remove()
}

Added benefit from this delegation is that adding the functionality to the "check" button is just

  if (e.target.innerText==="check") ...

I would recommend to use a class and testing

if (e.target.classList.contains("delete") 

instead of the innerText - especially if you want to change language of the button

const todo = document.getElementById('todo');
const enter = document.getElementById('enter');
const output = document.getElementById('output');
enter.addEventListener('click', () => {
  listItem(todo);
});
let createListItem;
var deleteBtn;
let checkBtn;

function listItem(todo) {
  let createListItem = document.createElement('li'); // use let or var here
  createListItem.innerText = todo.value;
  todo.value = '';

  output.appendChild(createListItem);

  checkBtn = document.createElement('button');
  deleteBtn = document.createElement('button');

  checkBtn.innerText = 'check';
  deleteBtn.innerText = 'delete';

  createListItem.append(checkBtn);
  createListItem.append(deleteBtn);

  checkBtn.classList.add('checkBtn');
  deleteBtn.classList.add('deleteBtn');

}
output.addEventListener('click', deleteFunc);

function deleteFunc(e) {
  console.log('function called');
  const tgt = e.target;
  if (e.target.innerText==="delete") tgt.closest("li").remove()
}
<section class="controls">
  <div>
    <label for="todo">Enter a to-do</label>
    <input type="text" name="todo" id="todo">
  </div>
  <span>
    <button id="enter" class = "enter"><i class="fas fa-paper-plane"></i></button>
  </span>
</section>
<section>
  <ul id="output" class="output">

  </ul>

</section>


推荐阅读