admin管理员组

文章数量:1302267

I am new to JS and I have a page with 2 filters, I am stuck and I am trying to:

  1. check automatically the (All) checkbox if every other checkbox of the filter are checked.

  2. when a user unchecked a checkbox, automatically uncheck the (All) checkbox.

I am trying the following code but it is not really working...

HTML:

<div id="filter1">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>

<div id="filter2">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>

JS:

$(".checkboxlistitem").change(function() {
$(".select-all").prop("checked", $(".checkboxlistitem:checked").length ==    $(".checkboxlistitem").length);});

JSFIDDLE:

/

Let me know if you need clarifications, Thanks in advance, Max

I am new to JS and I have a page with 2 filters, I am stuck and I am trying to:

  1. check automatically the (All) checkbox if every other checkbox of the filter are checked.

  2. when a user unchecked a checkbox, automatically uncheck the (All) checkbox.

I am trying the following code but it is not really working...

HTML:

<div id="filter1">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>

<div id="filter2">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>

JS:

$(".checkboxlistitem").change(function() {
$(".select-all").prop("checked", $(".checkboxlistitem:checked").length ==    $(".checkboxlistitem").length);});

JSFIDDLE:

https://jsfiddle/Max06270/5scgbnww/

Let me know if you need clarifications, Thanks in advance, Max

Share Improve this question edited Aug 18, 2016 at 22:33 Max06270 asked Aug 18, 2016 at 22:27 Max06270Max06270 671 silver badge9 bronze badges 4
  • What about it isn't working? When I run your Fiddle, the only thing I see happening that I wouldn't want to happen is that both "All" checkboxes get unchecked. – Cole Twitchell Commented Aug 18, 2016 at 22:31
  • Yes that is the first thing. Also if you unselect everything and you select chexboxes one by one exept the (All), (All) checkbox is not getting checked by iteself. – Max06270 Commented Aug 18, 2016 at 22:35
  • Both problems are happening because your filters use the same classes for their elements. Splitting them up to use separate classes will fix this, for example: class="select-all-1" and class="select-all-2". You'll also have to modify the checkboxlistitem classes and repeat that JS function for your other filter and its classes. – Cole Twitchell Commented Aug 18, 2016 at 22:40
  • Hum... my app has actually 15 filters, I was expecting to find a global solution. Thanks for your help – Max06270 Commented Aug 18, 2016 at 22:42
Add a ment  | 

3 Answers 3

Reset to default 5

You're jquery selectors were too generic, so they were affecting both forms. Below should be a working example of what you want:

$(".select-all").change(function () {
    $(this).siblings().prop('checked', $(this).prop("checked"));
});

$(".checkboxlistitem").change(function() {
	  var checkboxes = $(this).parent().find('.checkboxlistitem');
    var checkedboxes = checkboxes.filter(':checked');

    if(checkboxes.length === checkedboxes.length) {
     $(this).parent().find('.select-all').prop('checked', true);
    } else {
    $(this).parent().find('.select-all').prop('checked', false);
    }
});
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="filter1">
  <form action='#'>
    <input type="checkbox" value="all" class="select-all" checked>(All)<br>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1<br>
    <input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2<br>
    <input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3<br>
    <input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4<br>
    <input type="submit" value="Apply">
  </form> 
</div>

<br>

<div id="filter2">
  <form action='#'>
    <input type="checkbox" value="all" class="select-all" checked>(All)<br>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1<br>
    <input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2<br>
    <input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3<br>
    <input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4<br>
    <input type="submit" value="Apply">
  </form> 
</div>

https://jsfiddle/0epu6Lnn/

Fixing the form you have:

Your selectors of $('.checkboxlistitem') and $('.checkboxlistitem:checked') select all elements with those classes, and are therefor selecting the checkboxes in both forms. To fix this they need context.

Within jQuery's event callbacks, this refers to the element that the event is fired on. That means that we can use relative selectors to find the appropriate elements:

// find the nearest ancestor that's a form
$form = $(this).closest('form');

// find all the `.checkboxlistitem` elements within the form
$checkboxes = $form.find('.checkboxlistitem');

// find the all checkbox within the form
$all = $form.find('.select-all');

// if there are any unchecked checkboxes the all option should be unchecked
$all.prop('checked', !$checkboxes.not(':checked').length);

// leaving this as it was in the jsfiddle
// Select/Unselect all chexboxes of the form
$(".select-all").change(function () {
    $(this).siblings().prop('checked', $(this).prop("checked"));
});

$('.checkboxlistitem').change(function () {
  var $form,
      $checkboxes,
      $all;
  
  // find the nearest ancestor that's a form
  $form = $(this).closest('form');
  
  // find all the `.checkboxlistitem` elements within the form
  $checkboxes = $form.find('.checkboxlistitem');
  
  // find the all checkbox within the form
  $all = $form.find('.select-all');
  
  // if there are any unchecked checkboxes the all option should be unchecked
  $all.prop('checked', !$checkboxes.not(':checked').length);
});
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="filter1">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>

<div id="filter2">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>


This is great and all, but lets take it up a notch by improving the accessibility of your form and the behavior of partially plete checkbox lists.

Form accessibility

Labels

As-is your checkboxes have no labels.

You added text after them, certainly, but a screen reader has no way of knowing what each checkbox represents.

To fix this, use <label> elements.

<form action="#">
  <label>
    <input type="checkbox" value="all" class="select-all" checked>
    (All)
  </label>
  <br>
  <label>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>
    F1: Value1
  </label>
  <br>
  ...
</form>

They can either have the checkbox nested or have their [for] attributes point to the [id] attributes of the <input> elements, or both.

<form action="#">
  <input type="checkbox" id="f1-all" value="all" class="select-all" checked> <label for="f1-all">(All)</label>
  <br>
  <input type="checkbox" id="f1-v1" value="v1" class="checkboxlistitem" checked> <label for="f1-v1">F1: Value1</label>
  <br>
  ...
</form>

Hierarchy

There's a different hierarchical relationship between the "all" checkbox and the individual F#: Value# checkboxes.

To fix this, use <fieldset> and <legend> elements.

<form action="#">
  <fieldset>
    <legend>
      <label>
        <input type="checkbox" value="all" checked>
        <span>Select All in Filter 1</span>
      </label>
    </legend>
    <label>
      <input type="checkbox" value="v1" checked>
      <span>F1: Value1</span>
    </label>
    <br>
    ...
  </fieldset>
</form>

Line separation

You're currently using <br> elements to separate the fields onto different lines.

<p> elements are often used.

<form action="#">
  <fieldset>
    <legend>...</legend>
    <p>
      <label>
        <input type="checkbox" value="v1" checked>
        <span>F1: Value1</span>
      </label>
    </p>
    ...
  </fieldset>
</form>

Names

You're using the [value] attributes, which is good, but none of the <input> elements have [name] attributes, which means that the data won't be sent to the server, and calling jQuery's .serialize() on the forms won't get you the appropriate data.

Set the [name] on the checkboxes that have important values (the "all" checkbox won't be necessary):

<form action="#">
  <fieldset>
    <legend>...</legend>
    <p>
      <label>
        <input type="checkbox" name="v1" value="1" checked>
        <span>F1: Value1</span>
      </label>
    </p>
    ...
  </fieldset>
</form>

Alternatively, you can set all the [name] attributes to filter and rely on the various values to produce query strings such as filter=v1&filter=v2, but this is an advanced technique that's likely going to run into bugs with querystring parsing, so proceed with caution.

Partially Complete Checkbox Lists

While it's nice to be able to automatically uncheck the "all" checkbox, when some checkboxes are checked and other checkboxes are unchecked the unchecked state doesn't exactly make sense for the "all" checkbox. It's not at "none" and it's not at "all".

Enter the indeterminate state.

Checkboxes have a third state that's only accessible from JavaScript that was designed for exactly this situation.

You can set a given checkbox to the indeterminate state by toggling its indeterminate property:

document.querySelector('input[type="checkbox"]').indeterminate = true;

or with jQuery:

$('input[type="checkbox"]').first().prop('indeterminate', true);

Checking whether the list is in an indeterminate state can be done by differentiating between:

  1. No checkboxes checked
  2. All checkboxes checked
  3. Some checkboxes checked and unchecked

In practice this might look something like:

checkedCount = $checkboxes.filter(':checked').length;

if (!checkedCount) {
  // no checkboxes checked
  $all.prop({
    checked: false,
    indeterminate: false
  });
} else if (checkedCount === $checkboxes.length) {
  // all checkboxes checked
  $all.prop({
    checked: true,
    indeterminate: false
  });
} else {
  // some checkboxes checked and unchecked
  $all.prop({
    indeterminate: true
  });
}

All Together Now

A fully fleshed out implementation of all of the above looks like:

$('.filter').on('change', '[value="all"]', function () {
  var $form,
      $checkboxes,
      $all;
  
  $form = $(this).closest('form');
  $checkboxes = $form.find('[name="filter"]');
  $all = $form.find('[value="all"]');
  
  $checkboxes.prop('checked', $all.prop('checked'));
}).on('change', '[name="filter"]', function () {
  var $form,
      $checkboxes,
      $all,
      checkedCount;
  
  $form = $(this).closest('form');
  $checkboxes = $form.find('[name="filter"]');
  $all = $form.find('[value="all"]');
  
  checkedCount = $checkboxes.filter(':checked').length;
  
  if (!checkedCount) {
    // no checkboxes checked
    $all.prop({
      checked: false,
      indeterminate: false
    });
  } else if (checkedCount === $checkboxes.length) {
    // all checkboxes checked
    $all.prop({
      checked: true,
      indeterminate: false
    });
  } else {
    // some checkboxes checked and unchecked
    $all.prop({
      indeterminate: true
    });
  }
});
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="filter1" class="filter">
  <form action='#'>
    <fieldset>
      <legend>
        <label>
          <input type="checkbox" value="all" checked>
          <span>Select All in Filter 1</span>
        </label>
      </legend>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v1" checked>
          <span>F1: Value1</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v2" checked>
          <span>F1: Value2</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v3" checked>
          <span>F1: Value3</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v4" checked>
          <span>F1: Value4</span>
        </label>
      </p>
    </fieldset>
    <input type="submit" value="Apply">
  </form>
</div>

<div id="filter2" class="filter">
  <form action='#'>
    <fieldset>
      <legend>
        <label>
          <input type="checkbox" value="all" checked>
          <span>Select All in Filter 2</span>
        </label>
      </legend>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v1" checked>
          <span>F2: Value1</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v2" checked>
          <span>F2: Value2</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v3" checked>
          <span>F2: Value3</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v4" checked>
          <span>F2: Value4</span>
        </label>
      </p>
    </fieldset>
    <input type="submit" value="Apply">
  </form>
</div>

for those that want to use vanilla js:

const checkboxes = document.getElementsByClassName("checkboxlistitem");
const selectAllBtn = document.getElementById("select-all");
for (let i = 0; i < checkboxes.length; i++) {
  checkboxes[i].addEventListener("change", () => {
    for (let i = 0; i < checkboxes.length; i++) {
      if (checkboxes[i].checked === false) {
        selectAllBtn.checked = false;
        break;
      } else {
        selectAllBtn.checked = true;
      }
    }
  });
}
// select all button

selectAllBtn.addEventListener("change", (event) => {
  for (let i = 0, n = checkboxes.length; i < n; i++) {
    checkboxes[i].checked = event.target.checked;
    
  }
});
<div id="filter1">
  <form action='#'>
    <input type="checkbox" value="all" id="select-all" checked>(All)<br>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1<br>
    <input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2<br>
    <input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3<br>
    <input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4<br>
    <input type="submit" value="Apply">
  </form> 
</div>

本文标签: javascriptAuto checkuncheck the quotAllquot checkboxStack Overflow