1

Possible Duplicate:
Javascript closure inside loops - simple practical example

I add event handlers to multiple hrefs on my website with JS like this:

function addButtonListener(){
  var buttons = document.getElementsByClassName("selLink");
  for (var i = 0; i < buttons.length; i++)
  {
      button.addEventListener('click',function() { addTosel(i); },true);
    }
  }
}

But unfortunately to addTosel is passed the last i not the i from the loop. How to pass i accordingly to the object being processed in this moment?

Community
  • 1
  • 1
Tom Smykowski
  • 25,487
  • 54
  • 159
  • 236
  • sounds like you're needing a 'bind' function to get aroudn the async code you've written. will post a quick answer soon – Christopher Sep 08 '12 at 12:15

3 Answers3

2

You need to create a closure:

function addButtonListener(){
    var buttons = document.getElementsByClassName("selLink");

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

        button.addEventListener('click', function(index) { 
            return function () {
                addTosel(index);
            };
        }(i), true);
    }
}

This way the scope of the handler is bound to the proper context of i.

See this article for more information on this subject.

jbabey
  • 45,965
  • 12
  • 71
  • 94
0

You need to bind the i variable to the function when its declared. like so

for (var i = 0; i < buttons.length; i++) {
  button.addEventListener('click',(function() { addTosel(this); }).bind(i) ,true);
}

Note: I just wrote the code from memory so it may not be perfect, but it is the sulution you're needing, for reference as to the proper way, ie with cross browser shims etc look at:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind

Christopher
  • 1,358
  • 17
  • 32
  • This would make the index a `Number` object. To keep it a primitive you'd need `"use strict";`. – pimvdb Sep 08 '12 at 12:20
0

If you're going to take the .bind approach, do it like this.

for (var i = 0; i < buttons.length; i++) {
   button.addEventListener('click', addTosel.bind(null, i), true);
}

This makes a new function with null bound as the this value since your function doesn't seem to need it, and the current i bound as the first argument.

Or make your own binder function

var _slice = Array.prototype.slice;
function _binder(func, ctx /*, arg1, argn */) {
    var bound_args = _slice.call(arguments, 2);
    return function() {
        return func.apply(ctx, bound_args.concat(_slice.call(arguments)));
    }
}

And then do this.

for (var i = 0; i < buttons.length; i++) {
   button.addEventListener('click', _binder(addTosel, null, i), true);
}
gray state is coming
  • 2,107
  • 11
  • 20