Adding a listener to an array of elements, need unique arguments for function on each item

StackOverflow https://stackoverflow.com/questions/23654151

  •  22-07-2023
  •  | 
  •  

Frage

I have a bit of HTML generated by PHP in the format of:

<div class=zoomButton>
<input type=hidden name=zoomURL value=*different per instance*>
</div>

I am trying to attach a listener (imageZoom(event, url)) to each of the class "zoomButton" elements, but call it with different arguments for each instance.

i.e.

var zoomButtonArray = document.getElementsByClassName('zoomButton');
for (i=0; i<zoomButtonArray.length; i++)
    {   
        var zoomURL = zoomButtonArray[i].children[0].value;
        zoomButtonArray[i].addEventListener("mousedown", function(){imageZoom(event,zoomURL);});
   }

however it seems that zoomURL is always the value of the very last element. How can I change my code/approach so that the argument passed to the listener is the correct one, and not the last one in the "zoomButtonArray" array?

Thanks

War es hilfreich?

Lösung

You need to wrap the event listener in a closure:

function makeEventListenerForZoomURL(zoomURL) {
  return function(event) {
    imageZoom(event, zoomURL);
  }
}

var zoomButtonArray = document.getElementsByClassName('zoomButton');
for (i=0; i<zoomButtonArray.length; i++)
{
  zoomButtonArray[i].addEventListener(
    "mousedown",
    makeEventListenerForZoomURL(zoomButtonArray[i].children[0].value)
  );
}

This can also be simplified using the ECMAScript5 forEach:

var zoomButtonArray = document.getElementsByClassName('zoomButton');
zoomButtonArray = Array.prototype.slice.call(zoomButtonArray, 0);
zoomButtonArray.forEach(function(node) {
  node.addEventListener("mousedown", function(event) {
    imageZoom(event node.children[0].value);
  });
});

The reason is that each time the for loop executes a new function is created, this new scope references the variable i but i changes each time the loop iterates. So by the time the event listener runs it looks at the value of i only to find that it is the last value when the for loop ended. By using a closure described above the scope created is unique to each iteration of the loop so that when the event listener finally executes the value of the wrapped variable (zoomURL or node in the examples above) will not have changed.

Here is a good article explaining closures in for loops: http://trephine.org/t/index.php?title=JavaScript_loop_closures

Andere Tipps

I think you are missing quotes around attributes. I just added quotes and the tested at jsFiddle (Fiddle link in comments) and it's working see to console in developer tool. it is iterating through each element as desired. Console screen shot

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top