1

I need to do something like this:

for(int i =0; i< results.length; i++){
    $('ul').append('<li>'+results[i].name+'</li>').bind('click',function(){
        doSomething(results[i]);
    })
}  

but when the click happens, the object passed to doSomething is undefined. How do I solve this?

Didier Ghys
  • 30,396
  • 9
  • 75
  • 81
roshanvid
  • 793
  • 6
  • 21
  • 1
    possible duplicate of [Access outside variable in loop from Javascript closure](http://stackoverflow.com/questions/1331769/access-outside-variable-in-loop-from-javascript-closure) – davin Feb 23 '12 at 09:47

3 Answers3

3

results[i] is only valid variable at the time machine is inside the for loop, later on, when event handler is triggered, result[i] is undefined.

That's why you need to ensure results[i] gets saved as variable in context of a function.

for(var i=0; i< results.length; i++){
    (function(result) {
        $('<li>'+result.name+'</li>').appendTo($('ul')).bind('click',function(){
            doSomething(result);
        })
    })(results[i]);
}

Here's working example http://jsfiddle.net/T9aUq/.

Edit: Actually to make it really work, I had to change the way events are registered - at first, click handler was binded to elements matching $('ul') instead of new li element (since append() function of jQuery doesn't return appended element, but rather sticks to previous scope (which was ul).

WTK
  • 16,583
  • 6
  • 35
  • 45
0

save your element first!

for(var i =0; i< results.length; i++){
    var element = results[i];
    var li = $('<li/>').html(element.name);
    $('ul').append(li);
    li.click(function(){
        doSomething(element);
    });
}  
silly
  • 7,789
  • 2
  • 24
  • 37
  • To elaborate on this answer; the issue is that `i` is constantly changing. – Shea Feb 23 '12 at 09:39
  • 1
    This won't work, because just as `i` changes, so does `element`. See the other answer that addresses the issue with closures. – davin Feb 23 '12 at 09:44
  • 1
    Your code is broken. For one, there's typo `int` instead of `var`, for two, the resulting handler would always fire `doSomething` function with last element of results array as argument. Check it out here: http://jsfiddle.net/9hTBa/ – WTK Feb 23 '12 at 09:46
0

I actually ran into this same problem recently... Silly is right, however the variables need some form of encapsulation:

for(var i =0; i< results.length; i++) doThisFirst(i);
function doThisFirst(index) {
    $('ul').append('<li>'+results[index].name+'</li>').bind('click',function(){
        doSomething(results[index]);
    })
}

If that doesn't work... Make sure you don't have a loop inside a loop with the same varname for the index:

for (var i = 0; ...) {
    for (var i = 0; ...) {
    }
}
Shea
  • 1,965
  • 2
  • 18
  • 42