1

See http://jsfiddle.net/tAfkU/

When I'm looping through an array, how can I refer to the correct element of the array when I've bound callbacks in the loop?

var items = ["a", "b", "c"];
for(var i in items) {
    var this_item = items[i];
    var new_li = $('<li>'+this_item+'</li>');
    new_li.bind('click', function() {
        alert(this_item); // this always alerts "c"
    });
    $('.container').append(new_li);
}
hughes
  • 5,595
  • 3
  • 39
  • 55

3 Answers3

3

You'll want to create a closure over that variable:

var createCallback;

createCallback = function(item) {
  return function() {
    alert(item);
  };
};
for(var i in items) {
    var this_item = items[i];
    var new_li = $('<li>'+this_item+'</li>');
    new_li.bind('click', createCallback(this_item));
    $('.container').append(new_li);
}

Remember that the bound function is called later then that loop finishes so the value of this_item is whatever it was set to lastly. Javascript doesn't create a new scope for every loop iteration so if you want to define callbacks you have to create one yourself. The only way you can create scopes in JS is via functions. So I wrote a function that binds the value as an argument and returns a new function that will now "remember" the proper value.

Jakub Hampl
  • 39,863
  • 10
  • 77
  • 106
0

The issue is that you bind all your element "clicks" to the same variable. And since you define this variable each time it iterates over a value in the array your clicks will always return the last value that was assigned to the variable (the c).

Heres a solution for getting the actual "value" since you set it within the list item you can just take the actual object and return the .text();

var items = ["a", "b", "c"];
for(var i in items) {
    var this_item = items[i],
        new_li = $('<li>'+this_item+'</li>');
    new_li.bind('click', function() {
        alert($(this).text());

        //alert(this_item); // this always alerts "c"
    });
    $('.container').append(new_li);
}
Bjørn Thomsen
  • 348
  • 2
  • 9
-1

Try using the .data() method in jQuery.

var items = ["a", "b", "c"];
for(var i in items) {
    var this_item = items[i];
    var new_li = $('<li>'+this_item+'</li>');
    new_li.data("item", this_item).bind('click', function() {
        alert($(this).data("item"));
    });
    $('.container').append(new_li);
}
Matt MacLean
  • 19,410
  • 7
  • 50
  • 53