Ways to remove newly added tasks using JavaScript function?

I have an existing list of li elements in my HTML that can be deleted using JavaScript. However, whenever I add a new li, the delete function no longer works on the newly added item. I suspect the issue lies within the current implementation of the for loop. Is there another method you would recommend to address this issue? I have already attempted using e.target.matches and e.target.tagName === 'SPAN'.

/* eslint-disable require-jsdoc */
/* eslint-disable no-invalid-this */
/* eslint-disable no-var */

// Select all necessary elements from the DOM
var deleteTodo = document.querySelectorAll('span');
var strikeThrough = document.querySelectorAll('li');
var input = document.querySelector('input');
var ul = document.querySelector('ul');

// Delete completed todos
for (var i = 0; i < deleteTodo.length; i++) {
    deleteTodo[i].addEventListener('click', function(e) {
        if (e.target.tagName === 'SPAN') {
        console.log('Span clicked');
        }
    });
}

// Apply strikethrough effect to completed todos
for (var i = 0; i < strikeThrough.length; i++) {
    strikeThrough[i].addEventListener('click', function(e) {
        if (e.target.matches('li')) {
        this.classList.toggle('done');
        }
    });
}

// Add a new todo task
input.addEventListener('keypress', function(e) {
    if (event.keyCode === 13) {
        var newTodo = input.value;
        var newLi = document.createElement('li');
        newLi.innerHTML = '<span>X</span> ' + newTodo;
        this.value = '';
        ul.appendChild(newLi);
    }
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link rel="stylesheet" href="style.css" />
    <title>2Do</title>
</head>
<body>
    <div class="container"></div>
    <h1>2-Do List</h1>
    <input type="text" placeholder="Add New Todo" />
    <div>
    <ul>
        <li><span>X</span> one</li>
        <li><span>X</span> Two</li>
        <li><span>X</span> Task Three</li>
    </ul>
    </div>
    <script src="script.js"></script>
</body>
</html>

Answer №1

The issue you're encountering does not lie within the loop itself, but rather with adding listeners to the span elements. When a new span element is added, a listener needs to be attached to it. Consider implementing something like this:

var deleteSpan = document.querySelectorAll('span');
var strikeThrough = document.querySelectorAll('li');
var input = document.querySelector('input');
var ul = document.querySelector('ul');

const attachListenersToSpans = function(spanList){
  for (var i = 0; i < spanList.length; i++) {
    spanList[i].addEventListener('click', function(e) {
      if (e.target.tagName === 'SPAN') {
        console.log('span clicked');
      }
    });
  }
}

// Deleting completed todos
attachListenersToSpans(deleteSpan);

// Applying strikethrough effect to completed todos
for (var i = 0; i < strikeThrough.length; i++) {
  strikeThrough[i].addEventListener('click', function(e) {
    if (e.target.matches('li')) {
      this.classList.toggle('done');
    }
  });
}

// Adding a new todo task
input.addEventListener('keypress', function(e) {
  if (event.keyCode === 13) {
    var newTodo = input.value;
    var newLi = document.createElement('li');
    newLi.innerHTML = '<span>X</span> ' + newTodo;
    this.value = '';
    ul.appendChild(newLi);
    deleteSpan = document.querySelectorAll('span');
    attachListenersToSpans(deleteSpan);
  }  
});

Answer №2

To ensure efficient event handling, you have two options: either attach a new event listener to each new object created, or utilize event delegation by targeting a higher level element.

// function to add a new task item
input.addEventListener('keypress', function(e) {
  if (event.keyCode === 13) {
    var newTodo = input.value;
    var newLi = document.createElement('li');

    var newSpan = document.createElement('span');
        newSpan.innerHTML = "x";
    newLi.innerHTML = ' ' + newTodo;
    newLi.prepend(newSpan);

    this.value = '';

    // event listener for deleting the task
    newSpan.addEventListener("click",function(e){
      /* Code for handling click on 'x' icon */
    }

    ul.appendChild(newLi);
  }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to rename a class of an image tag using jQuery

I need to update the class name in my image tag <img src="img/nex2.jpeg" class="name"> When hovering over with jquery, I want to add a new class to it. After hovering, the tag should appear as follows: <img src="img/nex2.jpeg" class="name seco ...

Looking to set up an event listener for a customized checkbox in a Kendo UI Grid column with Vue Js?

Can someone help me figure out why my method checkboxToggle() is not working when I click on the checkbox? Here is the code snippet: ` Methods:{ toggleTemplate(){ let template = `<label class="switch" > <input type= ...

Vue.js v-for dynamically creates HTML blocks that capture the state of collapse with two-way data binding

I am currently working on capturing the click action state within an HTML v-for generated block for a collapsible function. I have set up a data table and it seems that the state is being captured correctly. However, I am facing an issue where the displa ...

Is it possible to refresh the component view using the service?

I am interested in developing a NotificationService that will be utilized to showcase a notification from another section. My inquiry is, how can I refresh the view of a component using a service? My ultimate goal is to have the capability to embed a comp ...

What is the reason for requiring that the value type in a map must be uniform?

When using TypeScript, I expect the map type to be either a number or string, but unfortunately, an error is being reported. Click here for the Playground const map: Map<string, string | number> = new Map([ [ '1', &apo ...

Issue with Promise rejection not being caught in Node.js with ExpressNode.js and Express are not

Within my Express web application, I've created a function that outputs a Promise object. login: function(un, pass) { result = {}; var loginOk = new Promise( function (resolve, reject) { if (result.hasOwnPr ...

presentation banner that doesn't rely on flash technology

Looking to create a dynamic slideshow banner for my website inspired by the design on play.com. This banner will feature 5 different slides that transition automatically after a set time, while also allowing users to manually navigate using numbered button ...

Achieving a Transparent Flash overlay on a website without hindering its usability (attention, interaction, form submissions, etc.)

Currently, we are attempting to overlay a transparent flash on top of an iframe which loads external websites. Is there a method to configure the page in a way that allows the transparent flash to be displayed while still allowing interaction with the und ...

retrieve the responseText in an ajax request

I am looking to receive Ajax feedback. var response = $.ajax({ url : 'linkAPI', type : 'get', dataType: 'JSON' }); console.log(response); Only the respo ...

Using jQuery Datatables fnReloadAjax successfully triggers a reload of the data, however, it

In my jQuery datatable, I am utilizing the code below to refresh the data: $(".unread-rows").click( function(e) { e.preventDefault(); message_table.fnReloadAjax("/letters/ajax/inbox/1"); message_table.fnDraw(); $(this).addClass("active").s ...

Switch to display only when selected

When I click on the details link, it will show all information. However, what I actually want is for it to toggle only the specific detail that I clicked on. Check out this example fiddle Here is the JavaScript code: $('.listt ul').hide(); $( ...

How can you use a selector to filter Cheerio objects within an `each` loop?

As I work on parsing a basic webpage using Cheerio, I began to wonder about the possibilities at hand: Consider a content structure like this: <tr class="human"> <td class="event"><a>event1</a></td> <td class="nam ...

Looking to add a dynamic divider between two columns that can be adjusted in width by moving the mouse left and right?

If you're looking for an example of two columns adjusting their width based on mouse movement, check out this page from W3Schools. I'm trying to implement this feature in my React app, but I'm unsure of how to proceed. Below is the JSX code ...

The parent component can successfully call the setState function, but for some reason, the

In my code structure, I have the following setup (simplified): Here is the parent component: //code... const {handleClick} = useClick; <ul> {actions.map((action: string) => ( <li onClick={() => handleClick()} key={uuidv4()}> ...

What is the best way to store a file object in React's state?

I am currently working on setting the state for a file object that is being passed between modals before it is uploaded to the server. Below is the code snippet that demonstrates what I am attempting to achieve. const initialState = { selectedD ...

Using Vue3 to set attributes on web components

I recently developed a self-contained web component using Vite and Vue3 to replace outdated jQuery libraries. When this component is rendered in HTML, it appears like this: <custom-datepicker id="deliveryTime"> #shadow-root <div> ...

The Angular test spy is failing to be invoked

Having trouble setting up my Angular test correctly. The issue seems to be with my spy not functioning as expected. I'm new to Angular and still learning how to write tests. This is for my first Angular app using the latest version of CLI 7.x, which i ...

Utilizing Selenium and Python to extract data from JavaScript tables via web scraping

I've come across numerous articles about Web Scraping, but I'm still struggling to figure out how to locate specific elements on a website. The site where I want to scrape the tables can be found here: My target tables are: "TB01," "TB02," "TB0 ...

AngularJS Default Option Selection

I am encountering some difficulties with the preselection of a select-input in angularJS. The select-box is being populated by an array. <select class="form-control" ng-model="userCtrl.selected_country" ng-options="country.name for country in userCt ...

import the JSONP file from the local directory and assign it to a variable on

My current setup involves a local webpage that is loading a large JSON database file by utilizing a file named data.jsonp that contains data={a JSON dictionary of information}. I then import this file in my HTML using <script src="data.jsonp"& ...