Search code examples
jquerytreeview

How to close all open ul's


I have a treeview with accordion which is working, but I want to collapse all previously opened items when a different one is clicked.

For example, in my jsFiddle, clicking on 'Beverages' will expand it. Then clicking on 'Food' will expand that one. I want 'Beverages' to collapse when 'Food' is clicked on, and vice versa.

I tried adding a new class in addition to the caret class thinking to remove all caret-down classes prior to the toggler function but I couldn't figure out how to call it before that click function. Would someone please explain how to close all previous expanded items and then expand the one that was clicked on?

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");
  });
}
ul,
#myUL {
  list-style-type: none;
}

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

.box {
  cursor: pointer;
  -webkit-user-select: none;
  /* Safari 3.1+ */
  -moz-user-select: none;
  /* Firefox 2+ */
  -ms-user-select: none;
  /* IE 10+ */
  user-select: none;
}

.box::before {
  content: "\2610";
  color: black;
  display: inline-block;
  margin-right: 6px;
}

.check-box::before {
  content: "\2611";
  color: dodgerblue;
}

.nested {
  display: none;
}

.active {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<li>
  <span class="caret">Beverages</span>
  <ul class="nested">
    <li>Water</li>
    <li>Coffee</li>
    <li>
      <span class="caret">Tea</span>
      <ul class="nested">
        <li>Black Tea</li>
        <li>White Tea</li>
        <li>
          <span class="caret">Green Tea</span>
          <ul class="nested">
            <li>Sencha</li>
            <li>Gyokuro</li>
            <li>Matcha</li>
            <li>Pi Lo Chun</li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</li>
<li>
  <span class="caret">Food</span>
  <ul class="nested">
    <li>Water</li>
    <li>Coffee</li>
    <li>  
      <span class="caret">Tea</span>
      <ul class="nested">
        <li>Black Tea</li>
        <li>White Tea</li>
        <li>
          <span class="caret">Green Tea</span>
          <ul class="nested">
            <li>Sencha</li>
            <li>Gyokuro</li>
            <li>Matcha</li>
            <li>Pi Lo Chun</li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</li>


Solution

  • For this to work you need to remove the relevant classes from any .caret and its sibling ul.nested which is not a parent of the .caret which is clicked. This can be done most simply using a combination of jQuery's closest(), children(), ,parents() and find() methods. Try this:

    let $carets = $('.caret').on('click', e => {
      let $caret = $(e.target);
      
      // display the clicked item
      $caret.toggleClass('caret-down');
      $caret.closest('li').children('.nested').toggleClass('active');
      
      // hide the rest
      let $parentCarets = $caret.parents('li').children('.caret'); 
      $carets.not($parentCarets).removeClass('caret-down').closest('li').find('.nested').removeClass('active');
    });
    ul,
    #myUL {
      list-style-type: none;
    }
    
    #myUL {
      margin: 0;
      padding: 0;
    }
    
    .box {
      cursor: pointer;
      -webkit-user-select: none;
      /* Safari 3.1+ */
      -moz-user-select: none;
      /* Firefox 2+ */
      -ms-user-select: none;
      /* IE 10+ */
      user-select: none;
    }
    
    .box::before {
      content: "\2610";
      color: black;
      display: inline-block;
      margin-right: 6px;
    }
    
    .check-box::before {
      content: "\2611";
      color: dodgerblue;
    }
    
    .nested {
      display: none;
    }
    
    .active {
      display: block;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <ul>
      <li>
        <span class="caret">Beverages</span>
        <ul class="nested">
          <li>Water</li>
          <li>Coffee</li>
          <li>
            <span class="caret">Tea</span>
            <ul class="nested">
              <li>Black Tea</li>
              <li>White Tea</li>
              <li>
                <span class="caret">Green Tea</span>
                <ul class="nested">
                  <li>Sencha</li>
                  <li>Gyokuro</li>
                  <li>Matcha</li>
                  <li>Pi Lo Chun</li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
      <li>
        <span class="caret">Food</span>
        <ul class="nested">
          <li>Water</li>
          <li>Coffee</li>
          <li>
            <span class="caret">Tea</span>
            <ul class="nested">
              <li>Black Tea</li>
              <li>White Tea</li>
              <li>
                <span class="caret">Green Tea</span>
                <ul class="nested">
                  <li>Sencha</li>
                  <li>Gyokuro</li>
                  <li>Matcha</li>
                  <li>Pi Lo Chun</li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>