24

I have an array of objects (specifically easelJS images) - something like this:

var imageArray = new Array;
gShape  = new createjs.Shape();
// shape is something
imageArray.push(gShape);

What I want to do is have an event listener instead of:

gShape.addEventListener("click", function() {alert"stuff"});

I want the program to know specifically which region is clicked so that I can send an alert box in the following way:

imageArray[index].addEventListener("click", function(){
    alert " you clicked region number " + index}
Ryan Williams
  • 653
  • 3
  • 12
  • 28

6 Answers6

27

Sure. You can just use a closure to save the index of that iteration. Otherwise there are shared by the same function scope and will give you the value of the same iteration. Creating a separate function for each will save the state of that inside the function.

var imageArray = new Array;
gShape = new createjs.Shape();
 // shape is something
 imageArray.push(gShape); // Dumped all the objects

for (var i = 0; i < imageArray.length; i++) {
   (function(index) {
        imageArray[index].addEventListener("click", function() {
           console.log("you clicked region number " + index);
         })
   })(i);
}

or better

 for(var i = 0; i < imageArray.length; i++) {
       imageArray[i].addEventListener("click", bindClick(i));
 }

 function bindClick(i) {
    return function() {
        console.log("you clicked region number " + i);
    };
 }

ES6 to the rescue

let imageArray = [];
gShape = new createjs.Shape();
// shape is something
imageArray.push(gShape); // Dumped all the objects

for (let i = 0; i < imageArray.length; i++) {
  imageArray[i].addEventListener("click", function() {
    console.log("you clicked region number " + i);
  });
}

Using the let keyword creates a block scoping for the variable in iteration and will have the correct index when the event handler is invoked.

ed1nh0
  • 1,532
  • 13
  • 17
Sushanth --
  • 55,259
  • 9
  • 66
  • 105
  • 1
    You're welcome to do whatever, but I would just remove the first example. Not only is it what the other answers have, I don't think it should really ever be used when you can use something cleaner and more efficient like your second example – Ian Jul 31 '13 at 21:49
  • 5
    @Ian.. I agree with you .. But there might be cases when the user's might not understand how it actually works, unless there see a verbose example.. That is the reason I left out the first example so that they can compare how the 1st example can be written in a cleaner manner – Sushanth -- Jul 31 '13 at 21:51
  • Thanks @Sushanth-- - I end up end these "lambda lifting" situations before and can usually work out a better way, but it's good to see two side-by-side. – phatskat Aug 01 '13 at 03:09
8

Something like this should work:

for (var i = 0 ; i < imageArray.length ; ++i) {
    function(index) {
        imageArray[index].addEventListener("click", function() {
            alert ("You clicked region number: " + index");
        });
    } ( i);
}

The reason it works is because it creates a closure that holds the value of index that will be shown in the alert message. Each time through the loop creates another closure holding another value of index.

Lee Meador
  • 12,829
  • 2
  • 36
  • 42
2
//gShape must be an array of HTMLElement
gShape.forEach(element => element.addEventListener("click", function () {
    // this, refers to the current element.
    alert ("You clicked region number: " + this.getAttribute('data-region'));
}));
Sakis
  • 821
  • 7
  • 12
1

Sure, a closure is the solution, but since he's got Ext loaded he might as well use it and get some very readable code. The index is passed as the second argument to Ext.Array.each (aliased to Ext.each).

Ext.each(imageArray, function(gShape, index) {
    gShape.addEventListener("click", function() {
        alert("You clicked region number " + index);
    });
});
rixo
  • 23,815
  • 4
  • 63
  • 68
0

This is what I'm using for div id's:

var array = ['all', 'what', 'you', 'want'];

function fName () {
    for (var i = 0; i < array.length; i++)
    document.getElementById(array[i]).addEventListener('click', eventFunction);
};

Good Luck!

Caleb Mayhew
  • 58
  • 11
0

A simple way to do this, is by calling a querySelectorAll() on all the elements and using a loop to iterate and execute a function with the data of that specific array index once the EventListener is triggered by the element clicked.

Snippet

Retrieving the id attribute of the clicked element

document.querySelectorAll('li').forEach(element => {
  element.addEventListener('click', () => {              
    console.log(element.getAttribute('id'))
  })
})
li{cursor:pointer}
<ul>
  <li id="id-one">One</li>
  <li id="id-two">Two</li>
  <li id="id-three">Three</li>
  <li id="id-four">Four</li>
</ul>
Gass
  • 7,536
  • 3
  • 37
  • 41