How to check if all siblings (including selected) are checked with jQuery?

雨燕双飞 提交于 2021-02-11 07:20:43

问题


I'm trying to get only siblings of selected element but can't find a proper method for this or a way to achieve it. I always get the whole tree with find() method and with children() I can't get it to work.

This clicking should work like a checkbox tree:

If you click parent all children should be clicked and if you uncheck parent, all children must be unchecked.

But the thing that doesn't work is if you check a checkbox and all siblings are not clicked then the parent must indeterminate!

And also parent above must be undeterminate.

So what I actually need is to get the parent of selected checkbox and then collect the children and check if they all are checked. If yes then set parent as checked if not then parent must be indeterminate. But the problem is that jquery goes to deep.... and i need only the first children, and not everything underneath.

$(document).on('change', 'input.parent_cat_0', function() {
  var mainPermission = $(this);
  var mainPermissionChildren = mainPermission.parent().find('input:checkbox');
  if (mainPermission.is(':checked')) {
    mainPermissionChildren.each(function() {
      this.indeterminate = false;
      this.checked = true;
    });
  } else {
    mainPermissionChildren.each(function() {
      this.indeterminate = false;
      this.checked = false;
      $(this).removeClass("displayNone").next("img.tick").remove();
    });
  }
});

$(document).on('change', 'input.docPermission:not(.parent_cat_0)', function() {
  var selected = $(this);
  var liParents = selected.parents('li');
  var allCheckboxes = liParents.find('input:checkbox');
  var childrenOfSelected = selected.parent().find('input:checkbox');
  var upperParents = $(allCheckboxes).not(childrenOfSelected).get();

  if (selected.is(':checked')) {
    childrenOfSelected.prop('indeterminate', false);
    childrenOfSelected.prop('checked', true);

    //console.log('Total upper parents:', upperParents.length);

    $(upperParents).each(function (i,e) {
      // HOW TO GET ONLY FIRST SIBLINGS
      // For example if you click on Form 1
      // you should get only (Form 1a, Form 1b, Form 1c)
      // but NOT 'Form 1aa'
      //console.log($(e));
    });

  } else {
    childrenOfSelected.prop('indeterminate', false);
    childrenOfSelected.prop('checked', false);
  }


});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<li class="main">
  <input type="checkbox" id="cat_52" class="docPermission  parent_cat_0" name="localPerm[]">
  <label class="strong" for="cat_52">Forms</label>
  <ul>
    <li>
      <input type="checkbox" id="cat_53" class="docPermission  parent_cat_52" name="localPerm[]">
      <label class="strong" for="cat_53">Form 1</label>
      <ul>
        <li>
          <input type="checkbox" id="cat_55" class="docPermission  parent_cat_53" name="localPerm[]">
          <label class="strong" for="cat_55">Form 1a</label>
          <ul>
            <li>
              <input type="checkbox" id="cat_56" class="docPermission  parent_cat_55" name="localPerm[]">
              <label class="strong" for="cat_56">Form 1aa</label>
            </li>
          </ul>
        </li>
        <li class="main">
          <input type="checkbox" id="doc_80" class="docPermission  parent_cat_53" name="localPerm[]">
          <label for="doc_80">Form 1b</label>
        </li>
        <li class="main">
          <input type="checkbox" id="doc_82" class="docPermission  parent_cat_53" name="localPerm[]">
          <label for="doc_82">Form 1c</label>
        </li>
      </ul>
    </li>
    <li>
      <input type="checkbox" id="cat_54" class="docPermission  parent_cat_52" name="localPerm[]">
      <label class="strong" for="cat_54">Form 2</label>
    </li>
  </ul>
</li>

回答1:


You can try siblings() and andSelf()

$(document).on('change', 'input:checkbox', function(e) {
  const $this = $(this);

  if (!e.isTrigger) {
    $this
      .siblings('ul')
      .find('input:checkbox')
      .prop('checked', this.checked);
  }

  const $children = $this.parent('li').siblings().addBack();
  const $ckb = $children.find('> input:checkbox');

  const total = $ckb.length;
  const checked = $ckb.filter(':checked').length;
  const indeter = $ckb.filter(function() {
    return this.indeterminate;
  }).length;

  $this
    .parents('ul:first')
    .siblings('input:checkbox')
    .prop({
      checked: checked === total,
      indeterminate: indeter > 0 || (checked > 0 && checked < total)
     })
    .trigger('change')
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<ul>
  <li class="main">
    <input type="checkbox" id="cat_52" class="docPermission  parent_cat_0" name="localPerm[]">
    <label class="strong" for="cat_52">Forms</label>
    <ul>
      <li>
        <input type="checkbox" id="cat_53" class="docPermission  parent_cat_52" name="localPerm[]">
        <label class="strong" for="cat_53">Form 1</label>
        <ul>
          <li>
            <input type="checkbox" id="cat_55" class="docPermission  parent_cat_53" name="localPerm[]">
            <label class="strong" for="cat_55">Form 1a</label>
            <ul>
              <li>
                <input type="checkbox" id="cat_56" class="docPermission  parent_cat_55" name="localPerm[]">
                <label class="strong" for="cat_56">Form 1aa</label>
              </li>
            </ul>
          </li>
          <li class="main">
            <input type="checkbox" id="doc_80" class="docPermission  parent_cat_53" name="localPerm[]">
            <label for="doc_80">Form 1b</label>
          </li>
          <li class="main">
            <input type="checkbox" id="doc_82" class="docPermission  parent_cat_53" name="localPerm[]">
            <label for="doc_82">Form 1c</label>
          </li>
        </ul>
      </li>
      <li>
        <input type="checkbox" id="cat_54" class="docPermission  parent_cat_52" name="localPerm[]">
        <label class="strong" for="cat_54">Form 2</label>
      </li>
    </ul>
  </li>
</ul>



回答2:


Instead of relying on SomeParentCheckbox.trigger('change')
we could traverse parent groups recursively

  • On checkbox change, handle descendant checkboxes (any depth), set checked state same as the triggered one.
  • On checkbox change, recursively traverse parents to set checked or indeterminate attributes states

function handleDocPermParent(ckb) {
  // Get group element: (Ideally we would have a 'group' class, but sadly we don't, so let's go tricky for known common selectors)
  const $group = $(ckb).closest('ul');
  const $par   = $group.closest('li');
  
  if (!$par.length) return; // No parent? Recursion job done!
  
  const $par_ckb = $par.find(docPermClass).first(); // Find parent's main checkbox
  const $group_ckb = $group.children('li').children(docPermClass); // Collect all group's checkboxes
  
  const tot = $group_ckb.length; // How many checkboxes?
  const tot_checked = $group_ckb.filter(':checked').length; // How many siblings are checked?
  const tot_indeter = $group_ckb.filter((i, e) => e.indeterminate).length; // How many siblings are indeterminate?
  
  $par_ckb.prop({ // Finally set parent's main checkbox state:
    checked: tot_checked === tot,
    indeterminate: tot_indeter || tot_checked && tot_checked < tot
  });
  
  handleDocPermParent($par_ckb[0]); // Recursively iterate to outer parent
}

const docPermClass = '.docPermission';
const $docPerm = $(docPermClass);

$docPerm.on('change', function (evt) {
  const $ch = $(this).parent().find(docPermClass).not(this);
  $ch.prop({checked: this.checked}); // Handle inner checkboxes (in all childrens, any depth) explicitly:
  handleDocPermParent(this); // Handle parents recursively (from inner to outer) implicitly:
});
<ul>
  <li class="main">
    <input type="checkbox" id="cat_52" class="docPermission  parent_cat_0" name="localPerm[]">
    <label class="strong" for="cat_52">Forms</label>
    <ul>
      <li>
        <input type="checkbox" id="cat_53" class="docPermission  parent_cat_52" name="localPerm[]">
        <label class="strong" for="cat_53">Form 1</label>
        <ul>
          <li>
            <input type="checkbox" id="cat_55" class="docPermission  parent_cat_53" name="localPerm[]">
            <label class="strong" for="cat_55">Form 1a</label>
            <ul>
              <li>
                <input type="checkbox" id="cat_56" class="docPermission  parent_cat_55" name="localPerm[]">
                <label class="strong" for="cat_56">Form 1aa</label>
              </li>
            </ul>
          </li>
          <li class="main">
            <input type="checkbox" id="doc_80" class="docPermission  parent_cat_53" name="localPerm[]">
            <label for="doc_80">Form 1b</label>
          </li>
          <li class="main">
            <input type="checkbox" id="doc_82" class="docPermission  parent_cat_53" name="localPerm[]">
            <label for="doc_82">Form 1c</label>
          </li>
        </ul>
      </li>
      <li>
        <input type="checkbox" id="cat_54" class="docPermission  parent_cat_52" name="localPerm[]">
        <label class="strong" for="cat_54">Form 2</label>
      </li>
    </ul>
  </li>
</ul>

<script src="https://code.jquery.com/jquery-3.1.0.js"></script>


来源:https://stackoverflow.com/questions/56598635/how-to-check-if-all-siblings-including-selected-are-checked-with-jquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!