1

In my test code, I have a simple div that I'm using as a container for 5 loop created div elements. I try adding a click function to all 5 div elements, but only the last one is given a click function.

<div id="testbed"></div>

<script type="text/javascript">
$(document).ready(function () {
    for (i = 0; i < 5; i++) {
        $("#testbed").html($("#testbed").html() + "<div id='" + i + "'>Hello!</div>");
        $("#" + i).click(function () {
            alert(i);
        });
    }
});
</script>

Interestingly enough, instead of alerting 4, it alerts 5. I don't know why it's only applying the click function to the last div element and not the first 4.

Jay Sun
  • 1,583
  • 3
  • 25
  • 33
  • Hey, I appreciate the time that you guys put into this. A few of you have already posted working examples, and I'll be going through each response carefully, since you all used different examples. Thanks for the help. – Jay Sun Jul 20 '11 at 14:19

4 Answers4

2

All of your click handlers are sharing the same i variable.
Since, after the loop, i is 5, they all say 5.

You need to create each handler in a separate function that takes i as a parameter, so that each handler will get its own i.

For example:

function buildElement(i) {
    $("#testbed").html($("#testbed").html() + "<div id='" + i + "'>Hello!</div>");
    $("#" + i).click(function () {
        alert(i);
    });
}


for (i = 0; i < 5; i++) {
    buildElement(i);
}
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • How would that look like? Do I literally just create a new function outside of that loop, and loop through those div elements adding click functions? – Jay Sun Jul 20 '11 at 14:00
  • With that example, it still doesn't add the click function to the other divs. – Jay Sun Jul 20 '11 at 14:05
  • By re-setting the HTML, you're clearing any state in the DOM elements, including event handlers. You should call `append()` instead. – SLaks Jul 20 '11 at 14:06
  • Also, you should build the DOM element with jQuery and add the handler to it before appending, and not use an ID. (IDs, by the way, cannot start with a number) – SLaks Jul 20 '11 at 14:06
0

You could also do something to this effect:

$.each([1, 2, 3, 4, 5], function(index, value) { 
     $("#testbed").append("<div id='" + index + "'>Hello!</div>");
     $("#" + index).click(function () {
         alert(index);
     });
 });
Matthew D
  • 121
  • 1
  • 6
0

The following is called a javascript closure. At the moment of binding, you run the anonymous function that returns another function that does alert(i) when the event is fired. The first anonymous function "wraps" creates another level of variable scope for the i, so when the original i is incremented later on, the i inside the anonymous function remains untouched. Nifty little trick.

<div id="testbed"></div>

<script type="text/javascript">
$(document).ready(function () {
    for (i = 0; i < 5; i++) {
        $("#testbed").html($("#testbed").html() + "<div id='" + i + "'>Hello!</div>");
        $("#" + i).click(function (i) {
            return function(evt) {
                // inside here, you have access to the event object too
                alert(i);
            };
        }(i));
    }
});
</script>

More information at javascript closures

Btw if you wish to add click events to all divs, you can't replace them with .html() in every loop, use .append() instead, like so:

<div id="testbed"></div>

<script type="text/javascript">
$(document).ready(function () {
    for (i = 0; i < 5; i++) {
        $("#testbed").append("<div id='" + i + "'>Hello!</div>");
        $("#" + i).click(function (i) {
            return function(evt) {
                // inside here, you have access to the event object too
                alert(i);
            };
        }(i));
    }
});
</script>
Community
  • 1
  • 1
zatatatata
  • 4,761
  • 1
  • 20
  • 41
0

You need to add the click event to the object.

    $(function(){

      $('#testbed').empty();       

     for (i = 0; i < 5; i++) {
          $('<div />').text('Hello').attr('id', i).click(function(){
              alert($(this).attr('id'));
          }).appendTo('#testbed');
       }

    });
Simon
  • 2,810
  • 2
  • 18
  • 23