Home > OS >  Why is the initial state of my inputs ignored?
Why is the initial state of my inputs ignored?

Time:04-12

Please check out my fiddle below. A checkbox with nested checkboxes. The change function works fine: if any $('#checkbox' x) is checked, the corresponding $('.entry' x) shows, and if unchecked, hidden.

The initial state of my checkboxes is ignored until at least one of the checkboxes are clicked. In the example, initially all $('.entry' x) show, although #checkbox1, -2 and -3 are initially checked. But: if I then uncheck #checkbox2, only .entry1 and .entry3 show, all other elements hide. From there on, everything works as expected.

I've tried the following:

  1. $('#checkbox1').click(); so just clicking without "actually" clicking (leads to checkbox1 being unchecked but nothing else happens until I click on any of the checkboxes)

  2. setting a checkbox to .prop('checked', true) (pretty much the same result like in 1)

  3. I've also tried it with an if/else statement like

`

if ($('#checkbox'   x).prop('checked') == 'true') {
$('.entry'   x).show();
}
else{
$('.entry'   x).hide();
}`

Still nothing. How do I gain control over the initial states of the checkboxes in this example? Please help me, I just can't figure it out. Just to make clear what i want to achieve: I'd like to be able to set the props to checked and have the checked/unchecked " x" elements be hidden and shown accordingly, and create .on('click', ...) events to change the props later on and have them always behave accordingly.

 $(function () {
              // CHECKBOXES GROU AND NESTED CHECKBOXES HIDE/SHOW SYNCHRONIZING
              $.fn.nestedCheckboxes = function (stopPropogation) {
                this.addClass('nestedCheckboxes');
                this.on('click', ':has( > input[type=checkbox])', nestedCheckboxHandler);
                function nestedCheckboxHandler(evt) {
                  if ($(evt.target).is("input[type=checkbox]")) {
                    var parentContainer = $(this);
                    var checkbox = parentContainer
                      .find(' > input[type=checkbox]:eq(0)');
                    var parentCheckbox = parentContainer
                      .parent()
                      .closest(':has( > input[type=checkbox])')
                      .children('input[type=checkbox]');
        
                    if (evt.target == checkbox[0]) {
                      $('input[type=checkbox]', parentContainer)
                        .prop("checked", checkbox.prop("checked"));
                      $(function () {
                        $(new Array(5).fill(1).map((_, i) => i   1)).each(function (idx, x) { // Array for the number of div elements
                          $('.entry'   x)[($('#checkbox'   x).prop("checked") ? "show" : "hide")](); // synchronize
        
                          $('#checkbox'   x).on('change', function () {      // toggle on change     
                            $('.entry'   x).toggle();
                          });
                        });
                      });
                    }
                    var parentCheckboxValue = !parentCheckbox
                      .parent()
                      .find("input[type=checkbox]")
                      .not(parentCheckbox[0])
                      .is("input[type=checkbox]:not(:checked)");
        
                    parentCheckbox.prop("checked", parentCheckboxValue);
                  } else if (stopPropogation) {
                    evt.stopPropagation();
                  }
                };
              };
                $('.treeX-container form').nestedCheckboxes();
            });
* {
            list-style-type:none;
            }
            .l0{
            color: #000;
            font-weight: bold;
            }
            .entry1,
            .l1{
            color: #ff3333;
            }
            .entry2,
            .l2{
            color: #003DFF;
            }
            .entry3,
            .l3{
            color: #FF8A0E
            }
            .entry4,
            .l4{
            color: #45F300;
            }
            .entry5,
            .l5{
            color: #E700EF;
            }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            <div >
              <ul>
                <form>
                  <li>
                    <input type="checkbox"/>
                      <span >ALL</span>
                        <ul>
                          <li>
                            <input type="checkbox" id="checkbox1" value="1" checked />
                           <label >Entry1</label>
                          </li>
                          <li>
                            <input type="checkbox" id="checkbox2" value="1" checked />
                            <label >Entry2</label>
                          </li>
                          <li>
                            <input type="checkbox" id="checkbox3" value="1" checked />
                            <label >Entry3</label>
                          </li>
                          <li>
                            <input type="checkbox" id="checkbox4" value="1" />
                            <label >Entry4</label>
                          </li>
                          <li>
                            <input type="checkbox" id="checkbox5" value="1" />
                            <label >Entry5</label>
                          </li>
                       </ul>
                   </li>
                </form>
              </ul>
            </div>
            <div >
            <div >ENTRY1</div>
            <div >ENTRY2</div>
            <div >ENTRY3</div>
            <div >ENTRY4</div>
            <div >ENTRY5</div>
            </div>

CodePudding user response:

Here is a slightly simplified approach. showHideEntries() is a utility function that runs a loop over all checkboxes and sets the visibility of the associated entries below. It is called initially in the jQuery onl oad routine and later on whenever a checkbox is clicked.

$cb is a jQuery object that references all the "normal" (single) checkboxes.

$(function() {
  const $cb = $(".treeX-container")
    .on("click", "input", function() {
      if (!this.id)
        $cb.prop("checked", this.checked);
      showHideEntries();
    }).find("ul ul input");

  function showHideEntries() {
    $cb.each(function() {
      $("."   this.id.replace("checkbox", "entry")).toggle(this.checked)
    })
  }
  showHideEntries();
});
* {
  list-style-type: none;
}

.l0 {
  color: #000;
  font-weight: bold;
}

.entry1,
.l1 {
  color: #ff3333;
}

.entry2,
.l2 {
  color: #003DFF;
}

.entry3,
.l3 {
  color: #FF8A0E
}

.entry4,
.l4 {
  color: #45F300;
}

.entry5,
.l5 {
  color: #E700EF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <ul>
    <form>
      <li>
        <label ><input type="checkbox"/>
                      ALL</label>
        <ul>
          <li>
            <input type="checkbox" id="checkbox1" value="1" checked />
            <label  for="checkbox1">Entry1</label>
          </li>
          <li>
            <input type="checkbox" id="checkbox2" value="1" checked />
            <label  for="checkbox2">Entry2</label>
          </li>
          <li>
            <input type="checkbox" id="checkbox3" value="1" checked />
            <label  for="checkbox3">Entry3</label>
          </li>
          <li>
            <input type="checkbox" id="checkbox4" value="1" />
            <label  for="checkbox4">Entry4</label>
          </li>
          <li>
            <input type="checkbox" id="checkbox5" value="1" />
            <label  for="checkbox5">Entry5</label>
          </li>
        </ul>
      </li>
    </form>
  </ul>
</div>
<div >
  <div >ENTRY1</div>
  <div >ENTRY2</div>
  <div >ENTRY3</div>
  <div >ENTRY4</div>
  <div >ENTRY5</div>
</div>

Here is another answer to the extended question, as posted in your comment below (building on V2 of your JSfiddle):

$(function() {
  $(".treeX-container")
    .on("click", "input", function() {
      var $cb;
      if (!this.id){       // a group checkbox was clicked
        $cb=$("ul:first input",this.closest("li")); // get all subordinate checkboxes
        $cb.prop("checked",this.checked);           // and set them accordingly
      } else $cb=$(this);  // an individual checkbox option was clicked
      showHideEntries($cb);// update visibility of associated entry elements 
    });
  function showHideEntries($cb) {
    $cb.each(function() {
     if (this.id) $("."   this.id.replace("checkbox", "entry")).toggle(this.checked) 
    });
  }
  showHideEntries($("input"));
});
* {
  list-style-type: none;
  font-size: 14px;
}

.l0 {
  color: #000;
  font-weight: bold;
}

.container {}

.item {
  background-color: #999999;
  width: 20px;
  height: 20px;
  padding: 10px;
  line-height: 20px;
  display: inline-block;
  border-radius: 20px;
  text-align: center;
  vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <ul>
    <form>
      <li>
        <label ><input type="checkbox" />
        ALL</label>
        <ul>
          <li>
            <label><input type="checkbox" id="checkbox1" value="1" checked />
            Entry1</label>
          </li>
          <li>
            <label><input type="checkbox" id="checkbox2" value="1" checked />
            Entry2</label>
          </li>
          <li>
            <label><input type="checkbox" id="checkbox3" value="1" checked />
            Entry3</label>
          </li>
          <li>
            <label ><input type="checkbox" />
            CheckboxGroup</label>
            <ul>
              <li>
                <label><input type="checkbox" id="checkbox4" value="1" checked />
                Entry4</label>
              </li>
              <li>
                <label><input type="checkbox" id="checkbox5" value="1" checked />
                Entry5</label>
              </li>
              <li>
                <label><input type="checkbox" id="checkbox6" value="1" checked />
                Entry6</label>
              </li>
              <li>
                <label><input type="checkbox" id="checkbox7" value="1" />
                Entry7</label>
              </li>
              <li>
                <label ><input type="checkbox" />
                CheckboxGroup</label>
                <ul>
                  <li>
                    <label><input type="checkbox" id="checkbox8" value="1" checked />
                    Entry8</label>
                  </li>
                  <li>
                    <label><input type="checkbox" id="checkbox9" value="1" checked />
                    Entry9</label>
                  </li>
                  <li>
                    <label><input type="checkbox" id="checkbox10" value="1" checked />
                    Entry10</label>
                  </li>
                  <li>
                    <label><input type="checkbox" id="checkbox11" value="1" />
                    Entry11</label>
                  </li>
                  <li>
                    <label><input type="checkbox" id="checkbox12" value="1" />
                    Entry12</label>
                  </li>
                </ul>
              </li>
              <li>
                <label><input type="checkbox" id="checkbox13" value="1" />
                Entry13</label>
              </li>
            </ul>
          </li>
          <li>
            <label><input type="checkbox" id="checkbox14" value="1" />
            Entry14</label>
          </li>
          <li>
            <label><input type="checkbox" id="checkbox15" value="1" />
            Entry15</label>
          </li>
        </ul>
      </li>
    </form>
  </ul>
</div>
<div >
  <div >1</div>
  <div >2</div>
  <div >3</div>
  <div >4</div>
  <div >5</div>
  <div >6</div>
  <div >7</div>
  <div >8</div>
  <div >9</div>
  <div >10</div>
  <div >11</div>
  <div >12</div>
  <div >13</div>
  <div >14</div>
  <div >15</div>
</div>

I had to rearrange the logic a little bit to deal with the different sets of checkboxes it needs to collect. Center part is now the expression $cb=$("ul:first input",this.closest("li")); that collects all the checkboxes of the "next ul" in case one of the "collection" checkboxes was clicked. this.closest("li") (a Vanilla-JS expression!!!!) moves up to the closest li element and from there on the jQuery selector "ul:first input" will find all input elements below the first ul element it encounters.

I also changed your labels such that they always surround the associated checkbox. This way you can click on a label text to activate the checkbox inside the label.

  • Related