Nested parent/child checkboxes – working solution need adjustment help for Bootstrap

I have been looking for a ‘complete’ solution to nesting parent child checkboxes that change state correctly based on a hierarchy.

Most ‘solutions’ do not work or only work to one level. They also require you to name the checkboxes in a particular way.

  • JQuery: Checkbox Chain not working properly
  • How do you implement “check all” in react with child components?
  • How to enable radio group by checkbox?
  • “old” phones do not show the checkbox checkmark, when is checked via javascript
  • Removing from array values of checkboxes in jQuery
  • How do i disable a submit button when checkbox is uncheck?
  • This Stack Overflow discussion covers the main points but also provide a good solution discovered by Rory here.

    I have tested it within my development project and it works perfectly standalone. However, I am using Bootstrap 2.x and for checkboxes

    I have a JSFiddle which shows the working example code, then my version with a disabled parent checkbox and then the bootsrap code version which does not work.

    <!DOCTYPE html>
    <body>
    <!-- Raw working example from site http://css-tricks.com/indeterminate-checkboxes/ -->
    
    <b>Raw working example</b>
    <p>
    <ul>
        <li>
            <input type="checkbox" name="tall" id="tall">
            <label for="tall">Tall Things</label>
            <ul>
                <li>
                    <input type="checkbox" name="tall-1" id="tall-1">
                    <label for="tall-1">Buildings</label>
                </li>
                <li>
                    <input type="checkbox" name="tall-2" id="tall-2">
                    <label for="tall-2">Giants</label>
                    <ul>
                        <li>
                            <input type="checkbox" name="tall-2-1" id="tall-2-1">
                            <label for="tall-2-1">Andre</label>
                        </li>
                        <li>
                            <input type="checkbox" name="tall-2-2" id="tall-2-2">
                            <label for="tall-2-2">Paul Bunyan</label>
                            <ul>
                                <li>
                                    <input type="checkbox" name="tall-2-2-1" id="tall-2-2-1">
                                    <label for="tall-2-2-1">Son</label>
                                </li>
                                <li>
                                    <input type="checkbox" name="tall-2-2-2" id="tall-2-2-2">
                                    <label for="tall-2-2-2">Daughter</label>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </li>
                <li>
                    <input type="checkbox" name="tall-3" id="tall-3">
                    <label for="tall-3">Two sandwiches</label>
                </li>
            </ul>
        </li>
        <li>
            <input type="checkbox" name="short" id="short">
            <label for="short">Short Things</label>
            <ul>
                <li>
                    <input type="checkbox" name="short-1" id="short-1">
                    <label for="short-1">Smurfs</label>
                </li>
                <li>
                    <input type="checkbox" name="short-2" id="short-2">
                    <label for="short-2">Mushrooms</label>
                </li>
                <li>
                    <input type="checkbox" name="short-3" id="short-3">
                    <label for="short-3">One Sandwich</label>
                </li>
            </ul>
        </li>
    </ul>
    
    <hr>
    
    <!-- Non Bootstrap Example -->
    <b>My initial code example - Is Working</b>
    <p>
    <ul>
        <li>
    
            <input type="checkbox" name="" value="" disabled><strong>Ford</strong>
    
            <ul>
                <li>
    
                    <input type="checkbox" name="" value="">Fiesta</label>
                </li>
                <li>
    
                    <input type="checkbox" name="" value="">Focus</label>
                </li>
                <li>
    
                    <input type="checkbox" name="" value="">Mondeo</label>
                </li>
            </ul>
        </li>
        <li>
    
            <input type="checkbox" name="" value="" disabled><strong>Vauxhall</strong>
    
    
            <ul>
                <li>
    
                        <input type="checkbox" name="" value="">Corsa</label>
                </li>
                <li>
    
                        <input type="checkbox" name="" value="">Astra</label>
                </li>
                <li>
    
                        <input type="checkbox" name="" value="">Vectra</label>
                </li>
            </ul>
        </li>
    </ul>
    
                <hr>
    
    <!-- Bootstrap Example -->
    
    <b>Bootstrap based code example - Not Working</b>
    <p>
    
    <ul>
        <li>
            <label class="checkbox">
                <input type="checkbox" name="" value="" disabled><strong>Ford</strong>
    
            </label>
            <ul>
                <li>
                    <label class="checkbox">
                        <input type="checkbox" name="" value="">Fiesta</label>
                </li>
                <li>
                    <label class="checkbox">
                        <input type="checkbox" name="" value="">Focus</label>
                </li>
                <li>
                    <label class="checkbox">
                        <input type="checkbox" name="" value="">Mondeo</label>
                </li>
            </ul>
        </li>
        <li>
            <label class="checkbox">
                <input type="checkbox" name="" value="" disabled><strong>Vauxhall</strong>
    
            </label>
            <ul>
                <li>
                    <label class="checkbox">
                        <input type="checkbox" name="" value="">Corsa</label>
                </li>
                <li>
                    <label class="checkbox">
                        <input type="checkbox" name="" value="">Astra</label>
                </li>
                <li>
                    <label class="checkbox">
                        <input type="checkbox" name="" value="">Vectra</label>
                </li>
            </ul>
        </li>
    </ul>
    
    $(function () {
      // Apparently click is better chan change? Cuz IE?
      $('input[type="checkbox"]').change(function (e) {
          var checked = $(this).prop("checked"),
              container = $(this).parent(),
              siblings = container.siblings();
    
          container.find('input[type="checkbox"]').prop({
              indeterminate: false,
              checked: checked
          });
    
          function checkSiblings(el) {
              var parent = el.parent().parent(),
                  all = true;
    
              el.siblings().each(function () {
                  return all = ($(this).children('input[type="checkbox"]').prop("checked") === checked);
              });
    
              if (all && checked) {
                  parent.children('input[type="checkbox"]').prop({
                      indeterminate: false,
                      checked: checked
                  });
                  checkSiblings(parent);
              } else if (all && !checked) {
                  parent.children('input[type="checkbox"]').prop("checked", checked);
                  parent.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));
                  checkSiblings(parent);
              } else {
                  el.parents("li").children('input[type="checkbox"]').prop({
                      indeterminate: true,
                      checked: false
                  }); 
              } 
          } 
    
          checkSiblings(container); 
      }); 
    });
    

    My understanding is that the code needs to be changed somewhere to use parents or closest. Can someone who is a much better code please help identify where the change needs to happen to get the Bootstrap version working.

  • jquery get checkbox value if checked and remove value when unchecked
  • How can i get attribute value from a checkbox if it's checked?
  • jquery index() method problem selecting by attribute value
  • Change variable value when checkbox is checked/unchecked
  • jQuery Check if Checkbox is Checked, then Add Value to Input Field
  • dynamically create two column checkbox list in angular
  • 2 Solutions collect form web for “Nested parent/child checkboxes – working solution need adjustment help for Bootstrap”

    Take a look at the free JSTree user control. It is JavaScript-based, open source and allows to be configured for multiple styles of tree views, for example:

    enter image description here

    Since the checkboxes displayed here are just images, you can replace them by radio buttons easily, and via event handling you can disallow multiple selections so they behave like radio buttons if required.

    This is achieved by specifying the "checkbox" plugin as follows (see the JSFiddle I provided for the complete working code):

    $(function () {
        $("#demo1")
            .jstree({
            "themes": {
                "theme": "apple","dots": false,"icons": false
            },
            "plugins": ["themes", "html_data", "checkbox", "sort", "ui"]
        });
    });
    

    The corresponding HTML structure looks like this, just include it in the body of your page:

    <div id="demo1" class="demo" style="height:100px;">
        <ul>
            <li id="phtml_1">   <a href="#">Root node 1</a>
                <ul>
                    <li id="phtml_2">   <a href="#">Child node 1</a>
                    </li>
                    <li id="phtml_3">   <a href="#">Child node 2</a>
                    </li>
                </ul>
            </li>
            <li id="phtml_4">   <a href="#">Root node 2</a>
            </li>
        </ul>
    </div>
    

    To get the checked values, use this function (assuming you have created a div with id="listForDisplay" as I did in the JSFiddle example):

        function displayList() {
            var result=$("#listForDisplay");
            var checked = $("#demo1").jstree("get_checked", null, true);
            var selectedNodes="";
            result.text(selectedNodes);
            $(checked).each(function (i, node) {
                var id = $(node).attr("id");
                var text = $("#"+id).text();
                var parentId = $(node).attr("parentId");
                alert(parentId); alert(id);
                if (selectedNodes!=="") selectedNodes+=",";
                selectedNodes+=text;
            });
            result.text(selectedNodes);
        }
    

    This code can either be triggered in a click event or you can bind JSTree events like I did. Appending the following to the previous JavaScript snippet does the job:

        $("#demo1")
        .bind('loaded.jstree', function (e, data) {
                displayList();
            })
        .bind('change_state.jstree', function (e, data) {
                displayList();
            });
    

    The only issue is still that displayList() seems to produce duplicate entries when the entire parent is selected (meaning the parent names are listed along with the childs).

    You can find more about the options specifying the behaviour of this plugin here.

    you can try something like this

      $(function () {
      $('input[type="checkbox"]').change(function (e) {
          var checked = $(this).prop("checked"),
              container = $(this).closest("li"),//get closest li instead of parent
              siblings = container.siblings();
          container.find('input[type="checkbox"]').prop({
              indeterminate: false,
              checked: checked
          });
    
          function checkSiblings(el) {
              var parent = el.parent().parent(),
                  all = true,
                  parentcheck=parent.children("label");//get the label that contains the disabled checkbox
              el.siblings().each(function () {
                  return all = ($(this).find('input[type="checkbox"]').prop("checked") === checked);
              });
              //use parentcheck instead of parent to get the children checkbox
              if (all && checked) {
                  parentcheck.children('input[type="checkbox"]').prop({
                      indeterminate: false,
                      checked: checked
                  });
                  checkSiblings(parent);
              } else if (all && !checked) {
                  parentcheck.children('input[type="checkbox"]').prop("checked", checked);
                  parentcheck.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));
                  checkSiblings(parent);
              } else {
                 parentcheck.children('input[type="checkbox"]').prop({
                      indeterminate: true,
                      checked: false
                  });
              }
          }
          checkSiblings(container);
      });
    });    
    

    http://jsfiddle.net/Mvs87/2/