3

I'm still very new to Javascript / Jquery and understand very little so far, but I need a function for my website. (Im sure its easy but yeah, so far i have not come to any result xD)

So my problem:

I have a form with list of checkboxes, all shown in an tree view. I got the tree view from here.

So my structure is exacly like on the w3schools.com page with the same css and javascript with the only difference that instead of normal text I have a form with checkboxes, here I have created an example:

var toggler = document.getElementsByClassName("caret");
var i;

for (i = 0; i < toggler.length; i++) {
  toggler[i].addEventListener("click", function() {
    this.parentElement.querySelector(".nested").classList.toggle("active");
    this.classList.toggle("caret-down");
  });
}
/* Remove default bullets */
ul, #myUL {
  list-style-type: none;
}

/* Remove margins and padding from the parent ul */
#myUL {
  margin: 0;
  padding: 0;
}

/* Style the caret/arrow */
.caret {
  cursor: pointer;
  user-select: none; /* Prevent text selection */
}

/* Create the caret/arrow with a unicode, and style it */
.caret::before {
  content: "\25B6";
  color: black;
  display: inline-block;
  margin-right: 6px;
}

/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.caret-down::before {
  transform: rotate(90deg);
}

/* Hide the nested list */
.nested {
  display: none;
}

/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
.active {
  display: block;
}
<ul id="myUL">
  <li><span class="caret"></span><input type="checkbox" value="xyz" name="xyz">Beverages
    <ul class="nested">
      <li><input type="checkbox" value="xyz" name="xyz">Water</li>
      <li><input type="checkbox" value="xyz" name="xyz">Coffee</li>
      <li><span class="caret"></span><input type="checkbox" value="xyz" name="xyz">Tea
        <ul class="nested">
          <li><input type="checkbox" value="xyz" name="xyz">Black Tea</li>
          <li><input type="checkbox" value="xyz" name="xyz">White Tea</li>
          <li><span class="caret"></span><input type="checkbox" value="xyz" name="xyz">Green Tea
            <ul class="nested">
              <li><input type="checkbox" value="xyz" name="xyz">Sencha</li>
              <li><input type="checkbox" value="xyz" name="xyz">Gyokuro</li>
              <li><input type="checkbox" value="xyz" name="xyz">Matcha</li>
              <li><input type="checkbox" value="xyz" name="xyz">Pi Lo Chun</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

What i want now is: For example, if you select "Matcha" from my example, I would like all parent checkboxes to be selected, ie "Green Tea", "Tea" and "Beverages".

But i dont know how to do that :(

Can anyone help me out here?

cloned
  • 6,346
  • 4
  • 26
  • 38
iSkrumpie
  • 33
  • 5

2 Answers2

3

To achieve this you can traverse the DOM to find the checkbox elements which are children of the parents of the checked box.

As you've tagged the question with jQuery, here's a solution using that framework:

$('.caret').on('click', e => {
  let $target = $(e.target);
  $target.parent().children('.nested').toggleClass('active');
  $target.toggleClass('caret-down');
});

$(':checkbox').on('change', e => {
  if (e.target.checked) {
    $(e.target).parentsUntil('#myUL').children(':checkbox').prop('checked', true);
  }
});
ul,
#myUL {
  list-style-type: none;
}

#myUL {
  margin: 0;
  padding: 0;
}

.caret {
  cursor: pointer;
  user-select: none;
}

.caret::before {
  content: "\25B6";
  color: black;
  display: inline-block;
  margin-right: 6px;
}

.caret-down::before {
  transform: rotate(90deg);
}

.nested {
  display: none;
}

.active {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="myUL">
  <li><span class="caret"></span><input type="checkbox" value="xyz" name="xyz">Beverages
    <ul class="nested">
      <li><input type="checkbox" value="xyz" name="xyz">Water</li>
      <li><input type="checkbox" value="xyz" name="xyz">Coffee</li>
      <li>
        <span class="caret"></span>
        <input type="checkbox" value="xyz" name="xyz">Tea
        <ul class="nested">
          <li><input type="checkbox" value="xyz" name="xyz">Black Tea</li>
          <li><input type="checkbox" value="xyz" name="xyz">White Tea</li>
          <li>
            <span class="caret"></span>
            <input type="checkbox" value="xyz" name="xyz">Green Tea
            <ul class="nested">
              <li><input type="checkbox" value="xyz" name="xyz">Sencha</li>
              <li><input type="checkbox" value="xyz" name="xyz">Gyokuro</li>
              <li><input type="checkbox" value="xyz" name="xyz">Matcha</li>
              <li><input type="checkbox" value="xyz" name="xyz">Pi Lo Chun</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
0

here is a possible solution for your question.

  1. Here added classnames to every possible level of lists, like level1, level2, level3 etc.
  2. An event listener added for all the checkboxes (inside the function i have write the conditions only for level4!)
  3. In the event listener function the code only checks for the event target state, so there is an important...

TODO: Implement the logic which checks, if any other element is selected in the same level!!

The function:

let checks = document.querySelectorAll('input[type="checkbox"]');

checks.forEach((box) => {
  box.addEventListener('change', (e) => {
    var level = e.target.parentNode.parentNode.className;
    if (level == 'level4') {
      if (e.target.checked) {
        e.target.parentNode.parentNode.parentNode.querySelector('input').checked = true;
        e.target.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector('input').checked = true;
        e.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector('input').checked = true;
      } else {
        e.target.parentNode.parentNode.parentNode.querySelector('input').checked = false;
        e.target.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector('input').checked = false;
        e.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector('input').checked = false;
      }
    }
  });
});

A working fiddle.

Anyway, this way it is pretty much "manual work" needed, my answers purpose is only to help to find a way of possible logic to achive your goal!

dominagy
  • 141
  • 6