Showing/hiding divs based on checkbox using jQuery

2019-07-19 15:31发布

问题:

I have a form with a checkbox (contained within a label #contact). For the change action of this checkbox, I am showing/hiding a div (#options).

To ensure that if the checkbox is checked the #options div always is always shown (and avoid the situation where checking the checkbox actually hides the subjequent options), I am using this code:

$('#contact :checkbox').is(':checked') ? $("#options").show() : $("#options").hide();

This works fine. The problem I have is that instead of a single checkbox with an ID, I want to have multiple checkboxes. I want to show/hide the next instance of my .hidden class based on whether the previous checkbox (within a label with the class .trigger) is checked or not. I have tried this:

$(document).ready(function() {
    if( $('.trigger :checkbox').is(':checked') ) {
        $(this).parent().nextAll('ul.hidden').show();
    } else {
        $(this).parent().nextAll('ul.hidden').hide();
    }
});

But to no avail. The checkboxes are in an unordered list, like this:

<ul>
  <li><label class="trigger"><input type="checkbox" name="02" /> Trigger 1</label>
      <ul class="hidden">
        <li><label><input type="checkbox" name="02-sub1" /> Normal</label></li>
        <li><label><input type="checkbox" name="02-sub2" /> Normal</label></li>
      </ul>
  </li>
  <li><label><input type="checkbox" name="02" /> Normal</label></li>
  <li><label><input type="checkbox" name="03" /> Normal</label></li>
  <li><label class="trigger"><input type="checkbox" name="04" /> Trigger 2</label>
      <ul class="hidden">
        <li><label><input type="checkbox" name="04-sub1" /> Normal</label></li>
        <li><label><input type="checkbox" name="04-sub2" /> Normal</label></li>
      </ul>
  </li>
</ul>

I can't see where I'm going wrong here; presumably my selector is incorrect, but I've played around with the syntax for ages and not got anywhere. Thanks in advance (and thank you for reading this far).

回答1:

You need to run your code inside a change handler, so this refers to the checkbox you want, like this:

$(document).ready(function() {
   $('.trigger :checkbox').change(function() {
     if( $(this).is(':checked') ) {
       $(this).parent().nextAll('ul.hidden').show();
     } else {
       $(this).parent().nextAll('ul.hidden').hide();
     }
   });
});

...and that can be made much shorter with .toggle(bool), like this:

$(function() {
   $('.trigger :checkbox').change(function() {
     $(this).parent().nextAll('ul.hidden').toggle(this.checked);
   });
});

If you need it to run when the page loads, so the show/hide states match the checkbox, just call that change handler with .change() (shortcut for .trigger('change')), like this:

$(function() {
   $('.trigger :checkbox').change(function() {
     $(this).parent().nextAll('ul.hidden').toggle(this.checked);
   }).change();
});


回答2:

You know you can roll your own fields, right? The typical way to do that is with a "rel=" field that has no meaning in HTML but can be picked up and used in jquery.

if ($('#contact :checkbox').is(':checked')) {
    $("#" + $('#contact :checkbox').attr('rel')).show();
} else {
    $("#" + $('#contact :checkbox').attr('rel')).hide();
}

And then:

  <li><label class="trigger"><input type="checkbox" name="04" rel="hidden-04" /> Trigger 2</label>
      <ul class="hidden" id="hidden-04">
        <li><label><input type="checkbox" name="04-sub1" /> Normal</label></li>
        <li><label><input type="checkbox" name="04-sub2" /> Normal</label></li>
      </ul>
  </li>

So then, when the checkbox named 04 is checked, we look in its rel field for the id of the object to hide() or show(). I think that's a LOT easier than trying to walk the dom to find the target object.