开发者

jQuery event handler only works for first element

I can't seem to figure out why only the first element invokes my event handler that displays an alert. I found other similar questions on Stack Overflow that related to using IDs rather than classes, but that's not my issue.

When I click on the 'x' next to the first element it displays the alert as expected, but fails to do so for the other elements that were added dynamically with the append button.

Here's a minimal, but complete example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script>
<script type="text/javascript">

$(document).ready(function() {

   $(function() {

     $(".append").click(function(){

      $('.container').append('<div class="box"></div>')
      $('.box:last').append('<div class="text"><span>ABCDEFG</span><br/></div>')
      $('.box:last').append('<a href="#" class="test">x</a>')

     });

      $("a.test").click(function() {
      alert("works only for the first item in the list");


     });


   });


});

</script>
   <style>
      .box {
          padding:3px;
          margin-bottom:3px;
          border-bottom:2px solid #fff;
          width:550px;
      }
      .box:hover{background-color:#fff;}

      #container {
          position:relative;
      }

      .text {
          float:left;
          width:300px;
          font-size:13px;
      }
      .text span {
          font-size:18px;
          line-height:23px;
          font-weight:700;
      }

   </style>
</head>

<body>

   <div class="container">

     <input type="button" class="append" value="Append">

      <div class="box">
     <div c开发者_开发百科lass="text"><span>ABCDEFG</span></div>
     <a href="#" class="test">x</a>
     </div>

   </div>

</body>
</html>


change

$("a.test").click(function() {

to

$("a.test").live('click', function() {

The reason why only the first element is working is because at the time the click event is attached, there is only one <a> element on the page. You need to explicitly add the click event handler to every anchor that is created, or use live events instead. Read more about live event handlers.


Your event handler isn't being added to subsequently appended elements. There are several ways to attach the event handler dynamically. For newer versions of jQuery (1.7+), use the .on() function with a selector.

$('.container').on('click', 'a.live', function() { alert("I'm on"); });

Older versions of jQuery don't have .on(), so you can use .live(). However, one caveat is that .live() is deprecated in 1.7.

$('a.live').live('click', function() { alert("I'm live"); });

Even the jQuery team suggests using alternatives to .live(), regardless of the version of jQuery you are using. For versions older than 1.7, use .delegate().

$('.container').delegate('a.test', 'click', function() { alert("I'm delegated"); });


When you hook up event handlers with bind (click is a shortcut for bind("click", ...)), only elements that already exist are hooked up. New ones you add later are not.

You can use the live or delegate function, or the delegation features of the on function, or hook them up individually when you add them:

  • Live example - Using the latest jQuery and delegate (you can also use on, but I like how delegate documents my intent):

    jQuery(function($) {
    
      $("#theButton").click(function() {
        $("#container").append(
          "<div><a class='test' href='#'>X</a></div>"
        );
      });
    
      $("#container").delegate("a.test", "click", function() {
        alert("Clicked");
      });
    
    });
    
  • Live example - Using the latest jQuery and on (note that the order of arguments is different from delegate):

    jQuery(function($) {
    
      $("#theButton").click(function() {
        $("#container").append(
          "<div><a class='test' href='#'>X</a></div>"
        );
      });
    
      $("#container").on("click", "a.test", function() {
        alert("Clicked");
      });
    
    });
    
  • Live example - Using your jQuery vesion (1.3.0?!) and hooking them up as you add them:

    jQuery(function($) {
    
      $("#theButton").click(function() {
        $("<div><a class='test' href='#'>X</a></div>")
          .click(aTestClick)
          .appendTo("#container");
      });
    
      $("a.test").click(aTestClick);
    
      function aTestClick() {
        alert("Clicked");
      }
    
    });
    

Off-topic (slightly):

  1. jQuery 1.3.0 is nine releases and more than two years out of date. Current release (as of the original answer, March 2011) is 1.5.1, and even if you want to stick with the 1.3 tree, there were not one but two maintenance releases after 1.3.0.
  2. You're using two separate ready calls, first the explicit one, then an implicit one (your $ where you pass in a function). Only one is necessary.
  3. Strongly recommend not relying on semicolon insertion, it's the spawn of the devil. End your statements with semicolons, to ensure scripts can be minified/compressed/packed and just because the interpreter can guess wrong sometimes.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜