admin管理员组

文章数量:1401673

I have a for loop running in javascript. In this loop I am creating a list item and binding a click event to it. When I click this list item I want it to call a function with the data from the current loop object as a parameter.

The problem is, no matter what list item I click. The data that is being passed as the parameter is the last element of the object I am looping rather than the current one that is being clicked.

for(e in data) {

    var suggestItem = $('<li>'+ data[e]['name'] +'</li>');

    suggestItem.click(function() {
        $(this).addClass('activeSuggestion');
        suggestSelect(suggestField, data[e]);      
    });

    suggestList.append(suggestItem);

}

I think I understand why this happens but not sure how I should handle it.

I have a for loop running in javascript. In this loop I am creating a list item and binding a click event to it. When I click this list item I want it to call a function with the data from the current loop object as a parameter.

The problem is, no matter what list item I click. The data that is being passed as the parameter is the last element of the object I am looping rather than the current one that is being clicked.

for(e in data) {

    var suggestItem = $('<li>'+ data[e]['name'] +'</li>');

    suggestItem.click(function() {
        $(this).addClass('activeSuggestion');
        suggestSelect(suggestField, data[e]);      
    });

    suggestList.append(suggestItem);

}

I think I understand why this happens but not sure how I should handle it.

Share Improve this question asked Dec 26, 2011 at 19:30 Justin CarlsonJustin Carlson 2,7102 gold badges20 silver badges19 bronze badges 1
  • 1 possible duplicate of jQuery Event Handler created in loop – Pointy Commented Dec 26, 2011 at 19:34
Add a ment  | 

2 Answers 2

Reset to default 5

This is a classic Javascript closure question. When the click event is triggered (when you click on something), the loop has already finished executing. The value of e is whatever the last key in data is. The solution to the problem is to create a new scope inside of your loop.

for(var e in data) {
    (function(datum) {
        suggestList.append(
            $('<li>' + datum.name + '</li>')
            .click(function() {
                $(this).addClass('activeSuggestion');
                suggestSelect(suggestField, datum);      
            });
        );
    })(data[e]);
}

Javascript is function scoped, so whenever a new function is encountered, a new scope is created. The above code "traps" the value of data[e] into datum because it passes it as a parameter to the function. Another way to code it which may be less confusing:

for(var e in data) {
    (function() {
        var datum = data[e];
        suggestList.append(
            $('<li>' + datum.name + '</li>')
            .click(function() {
                $(this).addClass('activeSuggestion');
                suggestSelect(suggestField, datum);      
            });
        );
    })();
}

It doesn't pass in a parameter to the function, but because Javascript is function scoped, every time the click event is triggered it will look for where datum was assigned.

Also please note the for(VAR e in data) which will stop e from being a global variable.

You need to break the closure over e.

Since you're using jQuery, the easiest way would be to save the current value of e with jQuery's data function. Since all function parameters in JavaScript are passed by value, this effectively breaks the closure; now your click handler will work with what the value of e is when the handler was created, and not the value e holds when the loop ends.

for(e in data) {

    var suggestItem = $('<li>'+ data[e]['name'] +'</li>');

    suggestItem.data('savedE', e).click(function() {
        $(this).addClass('activeSuggestion');
        suggestSelect(suggestField, data[$(this).data('savedE')]);
    });

    suggestList.append(suggestItem);

}

本文标签: jqueryJavascript loop with binded click event always returning last resultStack Overflow