5

I have an array of objects that holds each "actionButton" id, selector and callback

var actionButtons = [
    {
        id:"0",
        selector:"._55ln._qhr",
        callback: undefined
    },
    {
        id:"1",
        selector:"._22aq._jhr",
        callback: undefined
    },
    .
    .
    .
];

What I'm trying to do is calling a function with a specific parameter from the array(the id) every time a selector is clicked.

for(var i=0;i<actionButtons.length;i++){
    $(document).on('click', actionButtons[i].selector, function() {
        makeAction(actionButtons[i].id);
        if (actionButtons[i].callback)
            actionButtons[i].callback(this);
    });
}

But this code is not working; it looks like every time the callback function is called the value of i is equal to the array size.

How can I solve this problem;ie. to make the value of the variable i become different for each callback.

Abozanona
  • 2,261
  • 1
  • 24
  • 60
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Mr. Alien Sep 11 '17 at 05:08

3 Answers3

5

The issue is because the i variable is being incremented in the loop. This means that when the first event handler actually runs after the loop completes, i is the maximum value, not 0.

To fix this you can use a closure:

for(var i = 0; i < actionButtons.length; i++) {
  (function(i) {
    $(document).on('click', actionButtons[i].selector, function() {
      makeAction(actionButtons[i].id);
      if (actionButtons[i].callback)
        actionButtons[i].callback(this);
    });
  })(i);
}
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
2

In order not to fall into closure ambush you may always use array methods like

actionButtons.forEach(function(ab) {
  $(document).on('click', ab.selector, function() {
    makeAction(ab.id);
    ab.callback && ab.callback(this);
  });
});
Mr. Alien
  • 153,751
  • 34
  • 298
  • 278
Redu
  • 25,060
  • 6
  • 56
  • 76
0

You can use let:

The let statement declares a block scope local variable, optionally initializing it to a value.

Let will assure you the closure.

for(let i=0;i<actionButtons.length;i++){
   $(document).on('click', actionButtons[i].selector, function() {
       makeAction(actionButtons[i].id);
       if (actionButtons[i].callback)
         actionButtons[i].callback(this);
     });
}
gaetanoM
  • 41,594
  • 6
  • 42
  • 61