开发者

Abstracting the adding of click events to elements selected by class using jQuery

I'm slowly getting up to speed with jQuery and am starting to want to abstract my code. I'm running into problems trying to define click events at page load.

In the code below, I'm trying to run through each div with the 'block' class and add events to some of its child elements by selecting them by class:

<script language="javascript" type="text/javascript">
$(document).ready(function (){

$('HTML').addClass('JS'); // if JS enabled, hide answers

 $(".block").each(function() { 
  problem = $(this).children('.problem');
  button = $(this).children('.showButton');

  problem.data('currentState', 'off');

  button.click(function() {
   if ((problem.data('currentState')) == 'off'){
    button.children('.btn').html('Hide');
    problem.data('currentState', 'on');
    problem.fadeIn('slow');
   } else if ((problem.data('currentState')) == 'on'){
    button.children('.btn').html('Solve');
    problem.data('currentState', 'off');
    problem.fadeOut('fast');
   }
   return false;

  });
 });
});
</script>

<style media="all" type="text/css">
.JS div.problem{display:none;}
</style>


<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 1</p>
    </div>
</div>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 2</p>
    </div>
</div>

Unfortunately using this, only the last of the divs' button actually works. The event is not 'localised' (if that's the right word for it?) i.e. the event is only applied to the last $(".block") in the each method.

So I have to laboriously add ids for each element and define my click events o开发者_如何学运维ne by one. Surely there's a better way! Can anyone tell me what I'm doing wrong? And how I can get rid of the need for those IDs (I want this to work on dynamically generated pages where I might not know how many 'blocks' there are...)

<script language="javascript" type="text/javascript">
$(document).ready(function (){

$('HTML').addClass('JS'); // if JS enabled, hide answers

 // Preferred version DOESN'T' WORK  
 // So have to add ids to each element and laboriously set-up each one in turn...

 $('#problem1').data('currentState', 'off');

 $('#showButton1').click(function() {
  if (($('#problem1').data('currentState')) == 'off'){
   $('#showButton1 > a').html('Hide');
   $('#problem1').data('currentState', 'on');
     $('#problem1').fadeIn('slow');
  } else if (($('#problem1').data('currentState')) == 'on'){
   $('#showButton1 > a').html('Solve');
   $('#problem1').data('currentState', 'off');
     $('#problem1').fadeOut('fast');
  }
  return false;

 });


 $('#problem2').data('currentState', 'off');

 $('#showButton2').click(function() {
  if (($('#problem2').data('currentState')) == 'off'){
   $('#showButton2 > a').html('Hide');
   $('#problem2').data('currentState', 'on');
     $('#problem2').fadeIn('slow');
  } else if (($('#problem2').data('currentState')) == 'on'){
   $('#showButton2 > a').html('Solve');
   $('#problem2').data('currentState', 'off');
     $('#problem2').fadeOut('fast');
  }
  return false;

 });

});
</script>

<style media="all" type="text/css">
.JS div.problem{display:none;}
</style>



<div class="block">
    <div class="showButton" id="showButton1">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem" id="problem1">
      <p>Answer 1</p>
    </div>
</div>

<div class="block">
    <div class="showButton" id="showButton2">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem" id="problem2">
      <p>Answer 2</p>
    </div>
</div>


edited because I found the HTML :)

First: you need to declare "button" and "problem" with the var keyword.

Next, the click handler will be called in the context of the target element, so you shouldn't reference "button" inside it but "$(this)" instead.

Next, you're going to need to come up with a way to relate each button to its corresponding "problem" element. The handler can find the companion "problem" using jQuery DOM traversal routines:

button.click(function() {
  var $button = $(this), $problem = $button.closest('div.block').find('.problem');
  if (($problem.data('currentState')) == 'off'){
    $button.children('.btn').html('Hide');
    $problem.data('currentState', 'on');
    $problem.fadeIn('slow');
  } else if (($problem.data('currentState')) == 'on'){
    $button.children('.btn').html('Solve');
    $problem.data('currentState', 'off');
    $problem.fadeOut('fast');
  }
  return false;
});

Now another alternative would be to use the live mechanism, which would let you create only one handler function. It'd be pretty similar to this, but instead of binding the handler to each "button" <div> you'd just set it up and reference the selector:

$('.button').live('click', function() {
  // as above
});


Sorry, not enough reputation to vote for any of the above as useful, which they most definitely were!

The answer was actually quite simple - as @patrick and @Pointy rightly pointed out, all I needed to do was to add the var keyword to declare my two variables. doh!

I couldn't actually get the code suggestions to work but mine works fine now that it's been fixed with your help. Thanks!

<!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>Untitled Document</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
    $(document).ready(function (){

    $('HTML').addClass('JS'); // if JS enabled, hide answers

     $(".block").each(function() { 
      var problem = $(this).children('.problem');
      var button = $(this).children('.showButton');

      problem.data('currentState', 'off');

      button.click(function() {
       if ((problem.data('currentState')) == 'off'){
        button.children('.btn').html('Hide');
        problem.data('currentState', 'on');
        problem.fadeIn('slow');
       } else if ((problem.data('currentState')) == 'on'){
        button.children('.btn').html('Solve');
        problem.data('currentState', 'off');
        problem.fadeOut('fast');
       }
       return false;

      });
     });
    });
    </script>

<style media="all" type="text/css">
.JS div.problem{display:none;}
</style>

</head>

<body>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 1</p>
    </div>
</div>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 2</p>
    </div>
</div>

<div class="block">
    <div class="showButton">
        <a href="#" title="Show solution" class="btn">Solve</a>
    </div>

    <div class="problem">
      <p>Answer 3</p>
    </div>
</div>

</body>
</html>
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜