Addeventlistener Using for Loop and Passing Values

addEventListener using for loop and passing values

Closures! :D

This fixed code works as you intended:

// Function to run on click:function makeItHappen(elem, elem2) {    var el = document.getElementById(elem);    el.style.backgroundColor = "red";    var el2 = document.getElementById(elem2);    el2.style.backgroundColor = "blue";}
// Autoloading function to add the listeners:var elem = document.getElementsByClassName("triggerClass");
for (var i = 0; i < elem.length; i += 2) { (function () { var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false); elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false); }()); // immediate invocation}
<div class="container">  <div class="one" id="box1">    <p class="triggerClass">some text</p>  </div>  <div class="two" id="box2">    <p class="triggerClass">some text</p>  </div></div>
<div class="container"> <div class="one" id="box3"> <p class="triggerClass">some text</p> </div> <div class="two" id="box4"> <p class="triggerClass">some text</p> </div></div>

Adding addEventListener() in loop only works for last button

The main problem is that you redefine the HTML of adiv completely every time you iterate. This means that any event handler you had already bound to a child element of adiv is lost the moment you do adviv.innerHTML = .... Although you assign the same HTML plus some new one, you don't assign the event handlers that were previously defined. So they are lost.

Only the event handler you assign at the last iteration is not destroyed in this way.

Solution

A quick solution would be to first loop to create all the HTML, and then do a separate loop to assign the event handlers:

// First add all the new content:
var html = adiv.innerHTML;
for (var i = 0; i < array_length; ++i) {
var obj = data.Items[i];

html += "<div class='row'><div class='center-div six columns'>" + obj.Event + ", " + obj.Location + "</div></div>";
html += "<div class='row'><div class='center-div six columns'>" + obj.Date + ", " + obj.Time + "</div></div>";
html += "<div class='row'><div class='center-div six columns'><button id='yay_button_" + i + "' class='button-primary'>Deltag</button></div></div>";
}
adiv.innerHTML = html;

// Now bind the event handlers
// By using "let" instead of "var" the right value is retained
// in the handlers
for (let i = 0; i < array_length; ++i) {
var elem = document.getElementById('yay_button_' + i);
elem.addEventListener('click', function() {
alert('id: ' + i);
});
}

If your browser does not support ES2015 (for let), then you can use bind:

for (var i = 0; i < array_length; ++i) {
var elem = document.getElementById('yay_button_' + i);
elem.addEventListener('click', function(i) {
alert('id: ' + i);
}.bind(null, i));
}

Adding event listener to multiple elements using for loop and passing different parameters

You can simply declare the variable in the loop with let instead of var that creates a block scope local variable.

var myArray = [  document.getElementById("mydiv0"),  document.getElementById("mydiv1"),  document.getElementById("mydiv2")];
function myFunction(x){ alert("my number is " + x);}
for(let i = 0; i < myArray.length; i++){ myArray[i].addEventListener("click", function(){myFunction(i);});}
<div id="mydiv0">Div 0</div><div id="mydiv1">Div 1</div><div id="mydiv2">Div 2</div>

JavaScript addEventListener in loop

There's a couple of things.

First you need to pass in i to the function:

(function (i) {
var currCat = cats[i];
...
}(i));

But the second point is more tricky. You're creating elements on the fly and trying to attach event listeners to them which doesn't work. What you need to take advantage of is event delegation - attaching an event listener to a parent element and catching the events that bubble up from the attached elements.

Some changes need to be made to your code to make this work.

1) Add a couple of data attributes to the image elements to reference the index of the cat, and the cat name:

<img data-name="' + currCat.name + '" data-index="' + i + '" + id="' + currCat.name + '-photo" src="' + currCat.photo + '">

2) Create the new event listener on the catDiv element, picking up the values from the clicked element's data set, passing in those values to inceaseCount.

catDiv.addEventListener('click', function(e) {
if (e.target && e.target.nodeName == "IMG") {
var data = e.target.dataset;
increaseCount(data.index, data.name + '-count');
}
});

3) Rewrite the increaseCount function to account for those changes.

function increaseCount(index, span) {
cats[index].count++;
document.getElementById(span).innerHTML = cats[index].count;
}

Working example

addEventListener() and removeEventListener() in loop with passing argument

update = document.getElementById("updateSchedule");
cancel = document.getElementById("cancelUpdate");

const id_list = ["SUN8", "SUN9", "SUN10", "SUN11", "SUN12", "SUN2",
"SUN3", "SUN4", "MON8", "MON9", "MON10", "MON11",
"MON12", "MON2", "MON3", "MON4"]

function startUpdate() {
update.style.display = "none"
cancel.style.display = "inline-block"
let cell;
for (let i = 0; i < id_list.length; i++) {
cell = document.getElementById(id_list[i])
cell.style.cursor = "pointer"
cell.addEventListener("click", showAlert);
}
}

showAlert = function (event) {
event.target.classList.add("bg-success");
}

function cancelUpdate() {
update.style.display = "block"
cancel.style.display = "none"
for (let i = 0; i < id_list.length; i++) {
cell = document.getElementById(id_list[i])
cell.style.cursor = "default"
cell.removeEventListener("click",showAlert)
}
}

Javascript multiple dynamic addEventListener created in for loop - passing parameters not working

Problem is closures, since JS doesn't have block scope (only function scope) i is not what you think because the event function creates another scope so by the time you use i it's already the latest value from the for loop. You need to keep the value of i.

Using an IIFE:

for (var i=0; i<names.length; i++) {
(function(i) {
// use i here
}(i));
}

Using forEach:

names.forEach(function( v,i ) {
// i can be used anywhere in this scope
});

call addEventListener in loop with variable

You need to put event listener mechanism inside closure, in laymen closure return value from inner function, you want your event listener should be present even after loop is executed or scope is finished.

You need to wrap whole event or getElementByid inside closure, here is code snippet

  for (var id = 1; id <= 2; id++) {
(function(id){
elem = document.getElementById("court" + id + "button");
elem.addEventListener(
"click",
function(event){wassern(id, event);},
false
);
elem = document.getElementById("court" + id + "xbutton");
elem.addEventListener(
"click",
function(event){abbrechen(id, event);},
false
);
})(id)
}

for getting event you can pass this, this refer to event inside addEventListner

Here is jsFiddle code http://jsfiddle.net/Xtgr4/

Hope above answer make sense to you

Applying an addEventListener in a loop

The issue appears to be that you are re-appending your child elements on each "refresh", which shifts the order of the elements and gives the illusion of refreshing multiple elements.

You need to differentiate between an initial render and subsequent refreshes.

I recommend that you remove the append from your render function and instead handle appending in your final for loop:

// And finally we render all the elements on the page  
for(el in elements){
elements[el].render(elements[el]);
elements[el].target.append(elements[el].element);
}

Note that there are multiple "issues" with your code, including global variables in several locations. And I'm not confident that your architecture will scale well. But, those issues are outside the scope of your question, and you'll learn as you go... no reason to expect that everyone will know everything, and you may find that your current solution works just fine for what you need it to do.

var data = {        data1 : 0      };            var elements = {              1 : {          target  : 'main',          value   : data,          element : 'div',          events  : {            click : 'add'          }        },                2 : {          target  : 'main',          value   : data,          element : 'div',          events  : {            click : 'add'          }        },                3 : {          target  : 'main',          value   : data,          element : 'div',          events  : {            click : 'add'          }        }            }      
// This is our main object, we define the properties only ... var _elem = function (props,id){
this.id = id; this.target = document.getElementById(props.target); this.element = document.createElement(props.element); this.events = props.events; this.value = props.value; }
// Then we add a method to render it on the page ... _elem.prototype.render = function(){ // I added the Object Id for debugging purposes this.element.innerHTML = this.value.data1 + ' ['+this.id+']'; }
// ... and another to change the underlying data and re - render it _elem.prototype.add = function(){ // Since the data is a reference to the same data object // We expect to change the value for all the elements this.value.data1++; this.render(); } // First we looop trough the array with the element definition and // Cast each item into a new element for(var el in elements){ elements[el] = new _elem(elements[el],el); }
// Then we apply the event listener (if any event description is present) for(var el in elements){
if(!elements[el].hasOwnProperty( 'events' )){ continue; } // We use the anonymous function here to avoid the "common mistake" (function() { var obj = elements[el]; var events = obj.events; for(ev in events){ obj.element.addEventListener(ev,function(){ obj[events[ev]]() }); } })(); } // And finally we render all the elements on the page for(var el in elements){ elements[el].render(elements[el]); elements[el].target.appendChild(elements[el].element); }
div {  padding: 10px;  border: solid 1px black;  margin: 5px;  display: inline-block;}
<html>
<head></head>
<body> <div id="main"></div></body>
</html>


Related Topics



Leave a reply



Submit