Search code examples
javascriptjquerywordpresscheckboxcmb2

How to check all child checkboxes


I am using cmb2 taxonomy_multicheck_hierarchical field type to display my categories in a hierarchical format, however I have a lot of terms and they are currently 3 levels deep in the hierarchy.

I would like to check all child terms if the parent term is checked, and uncheck all the child terms if the parent term is unchecked.

Below is the part of the rendered html that I need work with:

<ul class="cmb2-checkbox-list cmb2-list">
  <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location1" value="england" data-hash="6u5db7f23u40"> <label for="supplier_location1">England</label></li>
  <li class="cmb2-indented-hierarchy">
    <ul>
      <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location2" value="east-midlands" data-hash="6u5db7f23u40"> <label for="supplier_location2">East Midlands</label></li>
      <li class="cmb2-indented-hierarchy">
        <ul>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location3" value="derbyshire" data-hash="6u5db7f23u40"> <label for="supplier_location3">Derbyshire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location4" value="leicestershire" data-hash="6u5db7f23u40"> <label for="supplier_location4">Leicestershire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location5" value="lincolnshire" data-hash="6u5db7f23u40"> <label for="supplier_location5">Lincolnshire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location6" value="northhamptonshire" data-hash="6u5db7f23u40"> <label for="supplier_location6">Northhamptonshire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location7" value="rutland" data-hash="6u5db7f23u40"> <label for="supplier_location7">Rutland</label></li>
        </ul>
      </li>
      <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location8" value="east-of-england" data-hash="6u5db7f23u40"> <label for="supplier_location8">East of England</label></li>
      <li class="cmb2-indented-hierarchy">
        <ul>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location9" value="bedfordshire" data-hash="6u5db7f23u40"> <label for="supplier_location9">Bedfordshire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location10" value="cambridgeshire" data-hash="6u5db7f23u40"> <label for="supplier_location10">Cambridgeshire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location11" value="essex" data-hash="6u5db7f23u40"> <label for="supplier_location11">Essex</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location12" value="hertfordshire" data-hash="6u5db7f23u40"> <label for="supplier_location12">Hertfordshire</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location13" value="norfolk" data-hash="6u5db7f23u40"> <label for="supplier_location13">Norfolk</label></li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location14" value="suffolk" data-hash="6u5db7f23u40"> <label for="supplier_location14">Suffolk</label></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location15" value="scotland" data-hash="6u5db7f23u40"> <label for="supplier_location15">Scotland</label></li>
</ul>

The javascript code that I attempted is as follow:

jQuery( document ).ready(function( $ ) {

    $('#supplier_location_container input[type="checkbox"]').click(function(){
        $('input[type="checkbox"]', $(this).closest('li').next()).prop( 'checked', true );
    });

    $('#supplier_location_container input[type="checkbox"]:checked').click(function(){
        $('input[type="checkbox"]', $(this).closest('li').next()).prop( 'checked', false );
    });


});

However my code contains many errors! it doesnt allow me to uncheck all child boxes when I check the parent again and also when you check any box on the last level deep of the hierarchy it also checks the box directly next to it on the same level!

UPDATE:

I feel like I am making progress but I am not quiet there yet. My new code allows me to check all child checkboxes from the parent checkbox, however if I try to check any checkbox inside the last level deep of my hierarchy, it will always check the checkbox directly underneath it. For example if you check checkbox id supplier_location3, it will also check supplier_location 4!

$('#supplier_location_container input[type="checkbox"]').click(function(){

        if($(this).is(':checked')){
            $('input[type="checkbox"]', $(this).closest('li').next()).prop( 'checked', true );
        }else{
            $('input[type="checkbox"]', $(this).closest('li').next()).prop( 'checked', false );
        }


    });

Solution

  • Assuming, your target checkboxes all have class cmb2-option, and list items considered parents (or bottom level of hierarchy) are not supposed to have class cmb2-indented-hierarchy, and they're expected to check/uncheck child checkboxes within immediate <li> sibling, having class cmb2-indented-hierarchy, I would implement that logic the following way:

    $('.cmb2-option').on('click', function(){
      //grab parent checkbox state
    	const checkState = this.checked;
      //grab immediate sibling of parent <li> node
    	const childListItem = $(this).closest('li:not(".cmb2-indented-hierarchy")').next('li.cmb2-indented-hierarchy');
      //exit if no child list available
    	if(childListItem.length == 0) return;
      //iterate through child checkboxes and adjust their state according to parent
    	[...childListItem.find('.cmb2-option')].forEach(childCheckbox => childCheckbox.checked = checkState);
    });
    <!doctype html>
    <html>
    <head>
      <script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    </head>
    <body>
    <ul class="cmb2-checkbox-list cmb2-list">
      <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location1" value="england" data-hash="6u5db7f23u40"> <label for="supplier_location1">England</label></li>
      <li class="cmb2-indented-hierarchy">
        <ul>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location2" value="east-midlands" data-hash="6u5db7f23u40"> <label for="supplier_location2">East Midlands</label></li>
          <li class="cmb2-indented-hierarchy">
            <ul>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location3" value="derbyshire" data-hash="6u5db7f23u40"> <label for="supplier_location3">Derbyshire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location4" value="leicestershire" data-hash="6u5db7f23u40"> <label for="supplier_location4">Leicestershire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location5" value="lincolnshire" data-hash="6u5db7f23u40"> <label for="supplier_location5">Lincolnshire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location6" value="northhamptonshire" data-hash="6u5db7f23u40"> <label for="supplier_location6">Northhamptonshire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location7" value="rutland" data-hash="6u5db7f23u40"> <label for="supplier_location7">Rutland</label></li>
            </ul>
          </li>
          <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location8" value="east-of-england" data-hash="6u5db7f23u40"> <label for="supplier_location8">East of England</label></li>
          <li class="cmb2-indented-hierarchy">
            <ul>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location9" value="bedfordshire" data-hash="6u5db7f23u40"> <label for="supplier_location9">Bedfordshire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location10" value="cambridgeshire" data-hash="6u5db7f23u40"> <label for="supplier_location10">Cambridgeshire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location11" value="essex" data-hash="6u5db7f23u40"> <label for="supplier_location11">Essex</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location12" value="hertfordshire" data-hash="6u5db7f23u40"> <label for="supplier_location12">Hertfordshire</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location13" value="norfolk" data-hash="6u5db7f23u40"> <label for="supplier_location13">Norfolk</label></li>
              <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location14" value="suffolk" data-hash="6u5db7f23u40"> <label for="supplier_location14">Suffolk</label></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><input type="checkbox" class="cmb2-option" name="supplier_location[]" id="supplier_location15" value="scotland" data-hash="6u5db7f23u40"> <label for="supplier_location15">Scotland</label></li>
    </ul>
    </body>
    </html>