1

I would like to create some objects dynamically and bind events to them (not important what events).

I'm passing a number to the event in order to distinguish those items. There is my code:

$('#add_btn').click(function() {
    var cont = $('#buttons');

    for(var i=0; i<5; i++) {
        var new_btn = $('<input>').attr('type', 'button').val(i);

        new_btn.click(function() {
            alert(i);
        });

        cont.append(new_btn);
    }
});

When I click on any from newly created buttons, displayed number is 5.

I think that i variable is passing by reference, but the question is: how to avoid passing variable by reference? More, even if I crate new variable before binding event (so the reference should point to another object, for example new_val = i.toString()), value is still same for all buttons (then its 4, understandable).

I know that I can attach new_btn.data() and read it in event, but I'm not sure if it won't be an overhead.

Link to jsfiddle: http://jsfiddle.net/Jner6/5/.

marxin
  • 3,692
  • 3
  • 31
  • 44
  • 1
    Famous question: [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example). Scope... that is all. – Mr. Polywhirl Nov 05 '13 at 11:57
  • Thank you all for responses, closure is the keyword ;) – marxin Nov 05 '13 at 12:09

3 Answers3

2

Since you are using a closure scoped variable in a loop, inside the loop you need to create a private closure.

$('#add_btn').click(function () {
    var cont = $('#buttons');

    for (var i = 0; i < 5; i++) {
        (function (i) {
            var new_btn = $('<input>').attr('type', 'button').val(i);

            new_btn.click(function () {
                alert(i);
            });

            cont.append(new_btn);
        })(i)
    }
});
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
0

Seems like you run into closures issue, try this:

(function( i ) {
    new_btn.click(function() {
        alert(i);
    });
})( i );

This will create immediate invoked function that will closure your variable i so you can use it in future. For now you just overriding i variable in your for-loop so you will have always same value that will equal last for-loop iteration.

antyrat
  • 27,479
  • 9
  • 75
  • 76
0

Don't make functions within a loop.

DEMO

var cont = $('#buttons');

$('#add_btn').click(function() {

    for(var i=0; i<5; i++) {
      $('<input>', {type:'button', value:i}).appendTo( cont );
    } 

});

cont.on('click', ':button', function() {
    alert( this.value );
});
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313