Upon the second click, the addEventListener function is triggered

When using the window.addEventListener, I am encountering an issue where it only triggers on the second click. This is happening after I initially click on the li element to view the task information, and then click on the delete button which fires the event for reading the task information. The delete button is placed within the list element.

The list element has a click handler specifically for reading the task information.

The delete button has its own handler for removing the task. I make sure to attach these events with stop event propagation to prevent triggering events on the parent elements.

The main problem here is that addEventListener only responds after the second click.

Another issue arises when removing the eventListeners altogether: clicking on the delete button also ends up triggering the event to read the task information.

I am seeking some genuine solutions to resolve these issues. Any help would be greatly appreciated. Thank you!

Check out the working demo => Working Demo

Here's my code:

window.deleteTask = function deleteTask(id) {
 const deleteButton = document.getElementById(id);
  deleteButton.addEventListener(
    "click",
    (event) => {
      // event.preventDefault();
      let taskAppObj = new ToDoConstructor();
      taskAppObj.removetask(id);
      event.stopPropagation();
    },
    false
  );
};

window.getTaskInfo = function getTaskInfo(id) {
  const li = document.getElementById(`data-${id}`);
  li.addEventListener("click", (event) => {
    let taskAppObj = new ToDoConstructor();
    let task = window.storeContext.find((task) => task.id === id);
    taskAppObj.readTheTask(task);
  });
};

Answer №1

setTimeout(function () {
  start();
}, 1000);

const TaskConstructor = function () {
  this.taskList = [
    {
      id: 1,
      title: "Task 1",
      description: "Running",
      priority: 1
    },
    {
      id: 2,
      title: "Task 2",
      description: "Reading",
      priority: 2
    },
    {
      id: 3,
      title: "Task 3",
      description: "Walking",
      priority: 3
    },
    {
      id: 4,
      title: "Task 4",
      description: "Eating",
      priority: 4
    }
  ];
  this.displayTask = function (params) {
    const taskDiv = document.getElementById("task-info");
    const titleSpan = document.getElementById("titleSpan");
    const descrSpan = document.getElementById("descrSpan");
    const prioritySpan = document.getElementById("prioritySpan");

    taskDiv.setAttribute("class", "visible");

    titleSpan.innerHTML = params.title;
    descrSpan.innerHTML = params.description;
    prioritySpan.innerHTML = params.priority;
  };
  this.removeTask = function (id) {

    if (window.storeContext.length > 0) {
      this.taskList = [...window.storeContext];
    }

    this.taskList = this.taskList.filter((element) => element.id !== id);
    
    window.storeContext = [...this.taskList];

    retrieveTaskList();
  };
};

function start() {
  const taskManager = new TaskConstructor();
  window.storeContext = [...taskManager.taskList];
  retrieveTaskList();
}
document.addEventListener("DOMContentLoaded", function () {
  const taskListOfUl = document.getElementById("task-elements");

  taskListOfUl.addEventListener("click", function (event) {
    if (event.target.tagName === "BUTTON") {
      const id = event.target.id;
      deleteSelectedTask(id);
    } else if (event.target.tagName === "LI") {
      const id = event.target.id.split("-")[1]; 
      viewTaskInfo(id);
    }
  });
});

function deleteSelectedTask(id) {
  let taskManager = new TaskConstructor();
  taskManager.removeTask(id);
}

function viewTaskInfo(id) {
  let taskManager = new TaskConstructor();
  let task = window.storeContext.find((task) => task.id == id);
  taskManager.displayTask(task);
}

function retrieveTaskList() {
  let tasks = [...window.storeContext];
  
  const taskListOfUl = document.getElementById("task-elements");
  taskListOfUl.innerHTML = "";

  if (tasks && tasks.length > 0) {
    tasks.forEach((task) => {
      const listItem = document.createElement("li");
      listItem.id = `data-${task.id}`;

      const taskTitle = document.createElement("span");
      taskTitle.innerText = task.title;

      const deleteButton = document.createElement("button");
      deleteButton.innerText = "x";

      listItem.addEventListener("click", function (event) {
     
        if (event.target.tagName === "SPAN") {
          viewTaskInfo(task.id);
        }
      });

      deleteButton.addEventListener("click", function (event) {
        event.stopPropagation(); 
        deleteSelectedTask(task.id);
      });

      listItem.appendChild(taskTitle);
      listItem.appendChild(deleteButton);
      taskListOfUl.appendChild(listItem);
    });
  }
}

document.getElementById("app").innerHTML = `
<h1>Tasks</h1>
<div class=task-display-div>
  <div class=task-col>
    <header>Task List</header>
    <div>
      <ul id=task-elements>
      </ul>
    </div>
  </div>
  <div class=task-col>
    <header>
      Task Details:
    </header>
    <div id=task-info class=hidden>
      <div>
        <h5>Task Title: </h5><SPAN id=titleSpan></SPAN>
      </div>
      <div>
        <h5>Task Details: </h5><SPAN id=descrSpan></SPAN>
      </div>
      <div>
        <h5>It is a prio <SPAN id=prioritySpan></SPAN> task.</h5>
      </div>
  </div>
</div>
`;
body {
  font-family: sans-serif;
}

.task-display-div {
  display: flex;
  width: 90%;
}

.task-col {
  padding: 0px 10px;
  border-right: 1px solid;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app"></div>

  </body>
</html>

Making some updates to the code makes it work with just one click (see full page for result)

Answer №2

It is recommended to use createElement instead of a string literal and not pass an initial argument in any Event listener function; the event argument will always be provided by default, which is considered good practice.

function displayTaskList() {
  let tasks = [...window.storeContext];
  console.log("tasks", tasks);
  const taskListUl = document.getElementById("task-elements");
  taskListUl.innerHTML =
    tasks && tasks.length > 0
      ? tasks
          .map(
            (task) =>
              `<li id=data-${task.id} onclick="retrieveTaskInformation(event)" key=${task.id}>
                ${task.title}
                <button id=${task.id} onclick="removeTask(event)">X</button>
              </li>`
          )
          .join("<br/>")
      : null;
}

Retrieve Task Information

window.retrieveTaskInformation = function retrieveTaskInformation(event) {
  const id = event.currentTarget.id.split('-')[1];
  let taskAppObj = new ToDoConstructor();
  let task = window.storeContext.find((task) => task.id === Number(id));
  taskAppObj.readTheTask(task);
};

Delete Task

window.removeTask = function removeTask(event) {
  event.stopPropagation();
  const id = event.currentTarget.id;
  console.log("This is the delete function!");
  let taskAppObj = new ToDoConstructor();
  taskAppObj.removetask(Number(id));
}

This code has also been tested in CodeSandbox.

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

What is the best way to execute a JavaScript file with npm scripts?

Trying to use npm but encountering some issues. In my package.json file, I have: "scripts": { "build": "build.js" } There is a build.js file in the same folder that simply console.logs. However, when I execute npm run build I receive the error messag ...

Building upon the preceding inquiry, a ReferenceError has occurred due to the object being undefined

After researching online, I came across a similar question marked as a duplicate that brought me to this link: How do I return the response from an asynchronous call?. Even though I couldn't find a solution in that thread, it seems like I may need to ...

Is Protractor compatible with Internet Explorer 9?

For my Angular App that is running on IE9, I need to create end-to-end acceptance tests. I'm curious to know if the browser simulated by Protractor matches the behavior of IE9 or a newer version? ...

How can Redux help persist input value through re-rendering?

Handling Input Value Persistence in Redux despite Re-rendering? I am currently able to store and save input values, but only the data from one step ago. For example, when I click on the second input field, it displays the value from the first input fiel ...

There are no documents found by calling db.collection.find

Just getting started with my journey in learning Express, Node, and Mongojs! I decided to create a small MongoDB database called 'users' and when I run: db.users.find() in the Mongo shell, I receive an array of documents. In my Express app&ap ...

What is the optimal placement for promises in Angular: Factory or Controller?

In my application, I have a basic factory to manage API calls. Currently, the structure looks like this: .factory('apiFactory', function($http){ var url = 'http://192.168.22.8:8001/api/v1/'; return { getReports: function() { ...

What is the functionality of CSS radio tabs?

Can anyone provide a breakdown of how the final section of this code operates? Specifically: [type=radio]:checked { } [type=radio]:checked ~ .content { z-index: 1; } I am brand new to CSS and wanted to experiment with creating interactive CSS tabs, whi ...

end the node.js automated testing process

I'm currently using Jasmine and Zombie JS to create automated tests. I have integrated Drone.io for Continuous Integration, and the tests are executing successfully. However, there seems to be an issue where after passing the tests, the process does n ...

Trouble with HTML img srcset functionality?

I'm currently working on implementing responsive images, and while everything seems to be functioning correctly in the latest version of Firefox, I'm encountering issues with Safari and Chrome. <img src="/images/pages/arrivals/02_exterio ...

Angular error message: Trying to access the property 'name' of an undefined object leads to a TypeError

I'm having trouble phrasing this question differently, but I am seeking assistance in comprehending how to address this issue. The error message I am encountering is as follows: TypeError: _co.create is not a function TypeError: Cannot read property ...

Communication with child processes in node.js is not done using the child_process module

Hello Everyone, I'm currently experimenting with node.js to utilize JS plugins developed by others using the child_process API. However, I'm facing an issue where the child process is not able to communicate effectively with the parent process. ...

What steps can be taken to restrict users to providing only one comment and rating for each item?

In the backend controller, I have the following code snippet: 'use strict'; var Comment = require('../../../models/comment'); module.exports = { description: 'Create a Comment', notes: 'Create a comment&apos ...

Have you checked the console.log messages?

As a newcomer to web development, I hope you can forgive me if my question sounds a bit naive. I'm curious to know whether it's feasible to capture a value from the browser console and use it as a variable in JavaScript. For instance, when I enco ...

Tab Focus discrepancy observed in Mozilla browser

Tab Focus issue with elements on Mozilla Firefox: <div class="editor-field"> <div> <%: Html.TextBox(model => model.AddressLine1, new { maxLength = 30, style = "width:300px", tabinde ...

"Delightful Data Display: Achieving Ajax Triumph with

When I include the success function in my DataTable, the rows do not automatically fill up in the table. However, when I remove the success function everything works correctly, and the datatable fills with data as expected. I am trying to retrieve a messag ...

Creating a real-time text field update feature for a form using Google Script

One of my clients is dealing with a large number of contacts and to streamline the process, I created a form with a scrolling list for contact selection. However, the list has become too long to navigate easily. Is there a solution that would allow the c ...

Deactivated dropdown menu options with the help of Twitter's bootstrap framework

Using markup, I have created a dropdown menu utilizing Twitter Bootstrap. <ul class="nav pull-right"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Menu <b class="caret"></b>< ...

What is the best approach to integrating AJAX calls with promises in the Angular framework?

I'm facing an issue while using Angular promises with the $q service in my controller. Here's the code snippet: var myController = function ($scope, myService) { $scope.doSomething = function (c, $event) { $event.preventDefault(); ...

"Encountered an issue while querying data with mongoose find

Is there a mistake in my code? I'm trying to retrieve the names of the teams but getting undefined. The Team model does have a name property, so I'm not sure why it's not working. code: userRoutes.get('/wait', function (req, res ...

Tips for incorporating animation while altering element styles within JavaScript

I am looking to incorporate a sliding animation that moves the element downward when the display property is set to block, and upward when it's set to none or an empty string, here is the current JavaScript code I have: <script> function showQ ...