KDawg KDawg - 5 months ago 32
Javascript Question

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

I want to use event listeners to prevent event bubbling on a div inside a div with onclick functions. This works, passing parameters how I intended:

<div onclick="doMouseClick(0, 'Dog', 'Cat');" id="button_id_0"></div>
<div onclick="doMouseClick(1, 'Dog', 'Cat');" id="button_id_1"></div>
<div onclick="doMouseClick(2, 'Dog', 'Cat');" id="button_id_2"></div>

<script>
function doMouseClick(peram1, peram2, peram3){
alert("doMouseClick() called AND peram1 = "+peram1+" AND peram2 = "+peram2+" AND peram3 = "+peram3);
}
</script>


However, I tried to create multiple event listeners in a loop with this:

<div id="button_id_0"></div>
<div id="button_id_1"></div>
<div id="button_id_2"></div>

<script>
function doMouseClick(peram1, peram2, peram3){
alert("doMouseClick() called AND peram1 = "+peram1+" AND peram2 = "+peram2+" AND peram3 = "+peram3);
}

var names = ['button_id_0', 'button_id_1', 'button_id_2'];

for (var i=0; i<names.length; i++){

document.getElementById(names[i]).addEventListener("click", function(){
doMouseClick(i, "Dog", "Cat");

},false);

}

</script>


It correctly assigns the click function to each div, but the first parameter for each,
peram1
, is
3
. I was expecting 3 different event handlers all passing different values of
i
for
peram1
.

Why is this happening? Are the event handlers not all separate?

Answer

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
});