Monday, March 16, 2009

Only the last element is bound/inserted/etc. in your javascript code’s “for” loop

There is a common problem when you use javascript for loop to bind an event function or add a class that comes from looping selection’s attributes.

To make clear what I mean consider this example:

var lis = $('ul li');

for (var i = 0; i<lis.length; i++) {
    var id = lis[i].id;
    lis[i].onclick = function () {
        alert(id);
    };
} // All li's get and alert the last li's id

There is no obvious code syntax nor logical problem in this code. But you still will get last li’s id in alert window whichever li you click.

The solution to this problem is to rewrite your code similar to this one:

var lis = $('ul li');

for (var i = 0; i<lis.length; i++) {
    var id = lis[i].id;
    lis[i].onclick = function (the_id) {
        return function () {
            alert(the_id);
        };
    }(id);
}

Here, we are introducing another anonymous function which will be called immediately after it has been declared, because of the trailing () (in our case (id)) with the current id.

This solves the problem of all items in the loop getting the last arrays/elements/etc. attribute value (id/class/etc.).

5 comments:

  1. just a jquery 1.3.2 cool solution to this problem:

    $('ul li').live("click", function(){ alert ($(this).attr("id")); });

    ReplyDelete
  2. Carlos, this is actually the problem that is not related to binding event's to the new dom elements.

    This problem occures when you loop through the elements...

    ReplyDelete
  3. does this give a solution in the case off looping a function that loads html elements on a page and has to set the id off an element within

    because now, I get the same id for every element
    actually, the last one in the loop

    thanks, Richard

    ReplyDelete
  4. @Anonymous, I would suggest you do that on callback function of your AJAX load. Something like:

    $('#content').load('url.php', function(){
    // do it here
    });

    Or is it what you are doing and only the last id is set?!

    ReplyDelete
  5. Uzbekjon - You saved my life!

    This is for those who prefer binding:

    $(mySelecter).bind("click", function(the_id){
    return function () {
    alert(the_id);
    };
    }(id)
    );

    ReplyDelete