How to add event listeners to an array of objects
Asked Answered
M

6

25

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}
Mailand answered 31/7, 2013 at 21:36 Comment(6)
How is what you want different from what you have?Ormazd
It should work.. Have you tried it?Frankfrankalmoign
@Jeffman It looks like it's in a loop, where index wouldn't be correct in the callbackBignonia
Ah. I got hung up on the word "region"Ormazd
actually it's not, Apparently I was just trying to add eventListeners before I pushed in an object to my array I just noticed it this morning... i thought my syntax was just wrong... this question doesn't really make any sense.. but thanks for all the answers!!!Mailand
It is not related to extjs and tag should be removedFleenor
M
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.

Mother answered 31/7, 2013 at 21:45 Comment(3)
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 exampleBignonia
@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 mannerMother
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.Quinine
B
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.

Bogtrotter answered 31/7, 2013 at 21:44 Comment(1)
Someone probably didn't check the timestamp and thought you copied the above answer.Frowsy
D
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'));
}));
Dribble answered 4/6, 2020 at 17:18 Comment(0)
R
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);
    });
});
Redblooded answered 1/8, 2013 at 0:56 Comment(0)
B
1

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>
Beside answered 13/9, 2021 at 10:1 Comment(0)
B
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!

Bellinzona answered 27/6, 2016 at 1:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.