jdphenix
jdphenix

Reputation: 15445

Adding event handlers to dynamically added elements

The following example page appends three <button> tags based on the foo object, and when clicked, I expect them to output the values in foo. For example, clicking on the button with ID btn1, I expect to get the output Title:baz, ID:7198. However, every button press outputs Title:whizbang, ID:7119.

I believe the culprit is in the event handler for the buttons ($("#btn" + i).click(function()), but I'm not sure. I've stepped through it and when clicked, the value of i is 2, no matter which button is pressed.

How do I accomplish the behavior I am looking for? jQuery is not a requirement, but what I happen to be using.

<html>
<head>
<script type='text/javascript'>
var foo = {
  "foo": [
      {
          "title":"bar",
          "id":7826
      },
      {
          "title":"baz", 
          "id":7198
      }, 
      {
          "title":"whizbang", 
          "id":7119
      }
  ]
};
</script>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.11.1.min.js'></script>
<script type='text/javascript'>
$(document).ready(function() { 
  for (i in foo.foo) { 
      $("#content").append("<button type='button' id='btn" + i + "'>" + foo.foo[i].title + "</button>"); 
      $("#btn" + i).click(function() { 
          $("#result").append("<p>Title:" + foo.foo[i].title + ", ID:" + foo.foo[i].id + "</p>"); 
      }); 
  }
}); 

</script>
</head>
<body>
  <div id='content' />
  <div id='result' />
</body>
</html>

Upvotes: 1

Views: 107

Answers (2)

weeklyTea
weeklyTea

Reputation: 345

Maybe here is need to save value of var i for each iteration, for example, in closure: put function which you pass as argument in click(..) in wrapper function by this way:

$(document).ready(function() { 
    for (i in foo.foo) { 
        $("#content").append("<button type='button' id='btn" + i + "'>" + foo.foo[i].title + "</button>"); 
        $("#btn" + i).click((function(i){
            function() { 
                $("#result").append("<p>Title:" + foo.foo[i].title + ", ID:" + foo.foo[i].id + "</p>"); 
            }
        })(i)); 
    }
});

Upvotes: 0

Shmoopy
Shmoopy

Reputation: 669

fiddle showing this solution working

$(document).ready(function() { 
     for (var i = 0; i < foo.foo.length; i++) { 
         $("#content").append("<button type='button' class='btn' data-btnid='"+i+"'>" + foo.foo[i].title + "</button>"); 
     }

     $("#content").on("click", ".btn", function() {
         var btnid = $(this).attr("data-btnid");
         $("#result").append("<p>Title:" + foo.foo[btnid].title + ", ID:" + foo.foo[btnid].id + "</p>"); 
     });
});

Like others have said, you should change your loop. Other than that these are the changes I made:

  • All your buttons have the same behavior, so give them the same class rather than an id
  • put the button id in a custom attribute (data-btnid). Custom attributes start with data-.
  • For actually getting the behavior you want, you have to dynamically bind the click event. Essentially you use a selector to get the parent, in your case it's $("#content"), and bind a click event to children with the class btn. Then it accesses the button that was clicked's custom attribute data-btnid to get the id which is the index of the information in your array.

Upvotes: 1

Related Questions