Why does the code work in two different forEach functions when it doesn't work in just one forEach function?

Within my code, I am working with an array named 'filteredTasks'. For each task in this array, my goal is to generate a button inside a Div and assign an onclick function to that specific button. Initially, I attempted to achieve this by using a single forEach loop which can be seen in the first block below. However, this approach did not produce the intended result. Although the buttons were successfully created, only the last button received the onclick function. Upon further experimentation, I decided to split the code into two separate forEach callbacks as shown in the second part below. Surprisingly, this new method proved successful in assigning the onclick function to each button accordingly. This discrepancy perplexes me, and I am seeking insight from fellow developers. Can anyone enlighten me on the reason behind this behavior? I appreciate any assistance provided!

        filteredTasks.forEach(function(task) {
            var buttonId = task.taskName.replace(/\s/g, '') + 'Button'
            var taskHTML = `<button class="taskButton" id="${buttonId}">${task.taskName}</button>`;
            taskDiv.innerHTML += taskHTML;
            var button = document.querySelector(`#${buttonId}`);
            button.onclick = function() {performTask(task)};
        });
    };





        filteredTasks.forEach(function(task) {
            var buttonId = task.taskName.replace(/\s/g, '') + 'Button'
            var taskHTML = `<button class="taskButton" id="${buttonId}">${task.taskName}</button>`;
            taskDiv.innerHTML += taskHTML;
        });

        filteredTasks.forEach(function(task) {
            var buttonId = task.taskName.replace(/\s/g, '') + 'Button'
            var button = document.querySelector(`#${buttonId}`);
            button.onclick = function() {performTask(task)};
        });
    };

Answer №1

It seems like the issue lies in how you are handling DOM updates. Your current code is only attaching the event to the last button, which is a common problem when using for loops in vanilla JavaScript (source: this article). While switching to a forEach loop usually resolves this issue (see here), it may not work in your specific case.

As you've already discovered, breaking down the tasks into stages is a better approach. Instead of trying to do everything within one loop, create all the necessary HTML first, add it to the DOM, and then attach event listeners to all buttons at once by selecting them based on their class.

const filteredTasks = [{ taskName: 'bob' },{ taskName: 'dave' }];
const tasks = document.querySelector('#tasks');

// Use `map` to generate all the buttons
// Here, I opted for a data attribute over an actual id
const html = filteredTasks.map(task => {
  const buttonId = `${task.taskName.replace(/\s/g, '')}Button`;
  return `<button class="taskButton" data-id="${buttonId}">${task.taskName}</button>`;
}).join('');

// Insert the generated HTML into the DOM with one update
tasks.innerHTML = html;

// Retrieve all taskButton buttons by their class,
// and assign click event listeners to each of them
const buttons = document.querySelectorAll('.taskButton');
[...buttons].forEach(button => button.addEventListener('click', performTask, false));

// The `performTask` function extracts the clicked button's id from its dataset 
// and logs it to the console
function performTask(e) {
  const { dataset: { id } } = e.target;
  console.log(id);
}
<div id="tasks"></div>

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

Navigating geometry with three.js - tips for making movements

Struggling with aligning cubes accurately using a script that positions cubes of different width, height, and depth on the xAxis, yAxis, and zAxis. var geometry = new THREE.BoxGeometry(width, height, depth); var cube = new THREE.Mesh(geometry, material); ...

Navigating the loop in Vue using JavaScript

I'm facing an issue where I need to send data at once, but whenever I try sending it in a loop, I end up getting 500 duplicate id status errors. I have a hunch that if I click on something in JavaScript, the data might be sent all at once. assignment ...

Unable to modify the properties of a stateless child component

I'm completely new to React and I decided to create a basic comments application. My main objective was to let users change their display pictures by clicking the 'Change Avatar' button. https://i.sstatic.net/TqVe4.png However, I encountere ...

Error message: "No elements were found in Ember.js jQuery cycle slideshow"

As I transition a traditional HTML site to an Ember.js application, I encountered a problem with the jQuery Cycle slideshow plugin. With approximately 10 slideshows on the site, I aimed to create a reusable partial to pass data to. Although the data passi ...

Tips for sending a form using Angular 1.5.8 and Java Servlet via POST method

After reading various tutorials and online documentation, I'm still struggling to figure out how to pass parameters from a JSP form. Below is the JavaScript script I am using: var app = angular.module('myApp', []); app.controller('Form ...

I'm having trouble getting the animation to work with jQuery. Despite trying everything, the animation doesn't seem to respond to any button clicks

Issue: I am facing a problem where nothing happens when I click the menu on the HTML page. It seems like a total beginner mistake, but I can't seem to get it to work. I have checked the code, and alert works fine, indicating that jQuery is connected t ...

Executing a function from a JavaScript include within TypeScript code - what's the best way to go about it

I am currently utilizing stacktrace.js as an include in my code base. Within this include, there is a method available for retrieving the stacktrace by invoking StaceTrace.get() I am struggling to figure out how I can call this method from TypeScript. I ...

The Ajax function effortlessly receives the returned value and smoothly transitions to the error handling stage

When trying to retrieve data from an ajax request, my function needs to receive the returned data as an array of strings. During debugging, I am able to see the response, but at the same time, the error function is triggered. This is how my code looks: ...

Implementing json value extraction in javascript

Hello there! I'm currently having trouble constructing a JSON format. Here is the JSON response: { "txs": { "lock_time": 0, "ver": 1, "size": 372, "inputs": [ { &qu ...

Completely enlarge this inline-block CSS div scan-line

I am looking to create a unique scan line effect that gradually reveals text from left to right, mimicking the appearance of a cathode-ray burning text into a screen's phosphors. The concept involves sliding across black rows with transparent tips. Y ...

Display real-time export status improvement

Utilizing the Java Script below to display a loader once the Export To Excel button is clicked. <script type="text/javascript"> function showProgress() { var updateProgress = $get("<%= UpdateProgress1.ClientID %>"); updateP ...

Refreshing Angular Page

I'm looking for a way to reset my Angular page back to its original state with just one button click. I attempted to use the angular.copy method, but encountered an error. I have various scope and controller variables that I don't want to reset i ...

Extracting data from large Arrays in PHP

In my script, I store player data in an array that changes based on the number of players present. The structure of the array is as follows: Array ( [0] => Array ( [Id] => 0 [Name] => Playername1 [Fr ...

Retrieving a specific data point from the web address

What is the most efficient way to retrieve values from the window.location.href? For instance, consider this sample URL: http://localhost:3000/brand/1/brandCategory/3. The structure of the route remains consistent, with only the numbers varying based on u ...

Converting an array to a string within a JSON input in Laravel

I'm encountering an issue regarding the conversion of an array to a string while trying to input JSON data into a Laravel table. Here is the JSON data I'm working with: { "data": [ { "client_id": "3", "vehicle_id": "3", ...

Sending a multi-dimensional array to the server using PHP via POST

Similar Question: multi-dimensional array post from form I am looking to transfer data from the client to the PHP server using jQuery's $.post() method. Once the data reaches the server, I want the $_POST['myList'] variable to be in one ...

Browser fails to display input value when altered

I have noticed that when the value of the Input element changes, the browser does not display the updated value. However, you can verify this change by inspecting the DevTools in the browser. I am curious as to why the actual value of the Input element is ...

Ways to Execute the Constructor or ngOnInit Multiple Times

Here's the scenario I'm facing: I have developed an app with multiple screens. One of these screens displays a list of articles. When a user clicks on an article, they are directed to another screen that shows the details of that specific item. ...

Utilizing Mongoose to apply a single schema across various collections while enabling separate updates for each collection

In my comments.model file, I have declared 2 collections as follows: var mongoose = require('mongoose'); var Schema = mongoose.Schema; require('./util'); var currentDate = new Date().getDate(); var currentMonth = new Date().getMonth ...

Can we spice up the button with some animation while waiting for the ajax call to complete? Just a little something to

My HTML page features a button that triggers an AJAX call when clicked. During the call, the text on the button is replaced with animated dots to indicate progress. However, there is an issue where sometimes the call takes several seconds, while other time ...