8

I have a question about the .click function in Jquery. I have this code:

for (var i = 0; i < 5; i++) {
    var divTest = $('<div></div>');
    divTest.text("My Div " + i);
    divTest.click(function() {
        alert("Alert: Div " + i);
    });
    $('#myTest').append(divTest);
}​

I expected to add five divs to the "myTest" element and for each div the onclick function would show an alert with the corresponding div number.

The divs were added properly, but when I click on the divs I always get the alert with the text: "Alert: Div 5". Why? What I have to change to generate the behavior that I'm expecting?

Here is my jsFiddle: http://jsfiddle.net/BKFGm/2/

VisioN
  • 143,310
  • 32
  • 282
  • 281
Rafael
  • 1,655
  • 3
  • 17
  • 25

6 Answers6

11

In this case you should use closure:

(function(i) {
    divTest.click(function() {
        alert("Div: " + i);
    });
})(i);

DEMO: http://jsfiddle.net/BKFGm/4/


Another option is to pass i in the eventData map:

divTest.click({ i: i }, function(e) {
    alert("Div: " + e.data.i);
});

DEMO: http://jsfiddle.net/BKFGm/11/

Community
  • 1
  • 1
VisioN
  • 143,310
  • 32
  • 282
  • 281
  • Note that you're creating a new function object for each iteration, which may cause performance issues when there is a large number of iterations. A declared function would provide better performance in that case. – Fabrício Matté Oct 16 '12 at 22:06
  • OH I see. I didn´t know this term. Thanks for your time! I'll accept as soon as possible. – Rafael Oct 16 '12 at 22:09
  • @FabrícioMatté Agreed with your first note. Maybe `eventData` is a good alternative for such cases. – VisioN Oct 16 '12 at 22:13
5

Once again, a classic case of closures. i keeps getting incremented, whereas you want to anchor it in the click event. Try this:

for( i=0; i<5; i++) {
  (function(i) {
    // your code that depends on `i` here
  })(i);
}
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
0

This is a scope issue. Also, it's a very commonly asked question here.

The simple fix:

for(var i = 0; i < 5; i++){
     var divTest = $('<div></div>')
         divTest .text("My Div " + i);

    (function(index){
        divTest .click(function () {
             alert("Div: " + index);
                    });
    })(i);

        $('#myTest').append(divTest);
}
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
0

When the Alert happens, the variable i is already set to 5.

BoltBait
  • 11,361
  • 9
  • 58
  • 87
0

.click works in a different scope than your cycle and it is undefined when your click handler is executed, unless you have an other i variable on the global scope.

Reflective
  • 3,854
  • 1
  • 13
  • 25
0

You can also try this

$(function() {
    for(var i = 0; i < 5; i++){
        var divTest = $('<div/>', {
            'text':"My Div " + i,
            'click':(function(i){
                return function(){
                    alert("Div: " + i);
                }
            })(i)
        });
        $('#myTest').append(divTest);
    }
});​

DEMO.

The Alpha
  • 143,660
  • 29
  • 287
  • 307