How to collapse all other nodes in a bootstrap4 list?

1.7k views Asked by At

I'm attempting to use a Bootstrap 4 event to collapse expanded lists in a nav so that only one list is expanded at a time. However, this list is hierarchical in that list items can contain lists.

This code only works for the first level. However, if I select a sub list, it collapses the parent of the expanding list.

$('#sidebar ul ul').on('show.bs.collapse', function () {
    let expandedNode = $(this);
    let parents = expandedNode.parentsUntil("#sidebar");
    //let children = expandedNode.children();
    $("#sidebar ul.show").each(function (idx) {
        if ($(this) !== expandedNode && $.inArray($(this), parents) == -1) 
            $(this).collapse('hide');
    });
});

How can I modify this event handler so that it will leave the parent of a child list that is expanding, expanded? Another way to explain it is that i want to use nested lists like an accordion.

2

There are 2 answers

0
A. Meshu On

If you want to push on a button and toggle on every collapse you can do something like this:

const theBtn = document.querySelector('#swipCollapse'); // action button 
const togglers = document.querySelectorAll('.btn-link'); // each collaspe button
const content2Show = document.querySelectorAll('#accordion div.collapse'); // content to show
let checker = 0;
theBtn.addEventListener('click', function() { // on each click:
  for (var i=0; i < content2Show.length; i++) {
    content2Show[i].classList.add('hide'); // hide all content
  }
  for (var i=0; i < togglers.length; i++) { // loop the togglers    
    if (checker >= Number(togglers.length)) { checker = 0; }
    togglers[Number(checker)].click(); // click the next toggler
  }
  
  content2Show[checker].classList.remove('hide'); // force show the proper content
  ++checker; // the next click will do the same on the next content and button.
});
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>

<div class="container">
    <div id="accordion">
        <div class="card">
            <div class="card-header">
                <h5 class="mb-0 d-inline">
                    <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                      Collapsible #1
                    </button>
                 </h5>
                 <button id="swipCollapse" class="my-2 float-right">show one in a time</button>
            </div>
            <div id="collapseOne" class="collapse" aria-labelledby="headingOne" data-parent="#accordion">
                <div class="card-body" id="child1">
                    <h1>Hi there!</h1>
                    <div class="card">
                        <div class="card-header">
                            <a href="#" class="btn-link" data-toggle="collapse" data-target="#collapseOneA">Child A and Collapsible #2</a>
                        </div>
                        <div class="card-body collapse" data-parent="#child1" id="collapseOneA">Now me!</div>
                    </div>
                    <div class="card">
                        <div class="card-header">
                            <a href="#" class="btn-link" data-toggle="collapse" data-target="#collapseOneB">Child B and Collapsible #3</a>
                        </div>
                        <div class="card-body collapse" data-parent="#child1" id="collapseOneB">Now me!</div>
                    </div>
                </div>
            </div>
        </div>
        <div class="card">
            <div class="card-header">
                <h5 class="mb-0">
        <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapse4" aria-expanded="false" aria-controls="collapse4">
          Collapsible #4
        </button>
      </h5>
            </div>
            <div id="collapse4" class="collapse" aria-labelledby="heading4" data-parent="#accordion">
                <div class="card-body">Now me!</div>
            </div>
        </div>
        <div class="card">
            <div class="card-header">
                <h5 class="mb-0">
        <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapse5" aria-expanded="false" aria-controls="collapse5">
          Collapsible #5
        </button>
      </h5>
            </div>
            <div id="collapse5" class="collapse" aria-labelledby="heading5" data-parent="#accordion">
                <div class="card-body">Click again and we will start all over!</div>
            </div>
        </div>
    </div>
</div>

2
Ash On

If I understand correctly you are talking about using Bootstrap Collapse in your sidebar and each item may have sub items which are also expected to collapse.

Below is a working example of my understanding of your question. I took the code from Bootstrap 4 nested accordion and reproduced it here; credit for the solution goes to the author bgraham1125.

Another similar example is Bootstrap 4 nested accordion with Font-Awesome icons

<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
    <div id="accordion">
        <div class="card">
            <div class="card-header" id="headingOne">
                <h5 class="mb-0 d-inline">
                    <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                      Collapsible #1
                    </button>
                 </h5>
                 <a href="#" data-target="[data-parent='#child1']" data-toggle="collapse" class="my-2 float-right">toggle all</a>
            </div>
            <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
                <div class="card-body" id="child1">
                    <div class="card">
                        <div class="card-header">
                            <a href="#" data-toggle="collapse" data-target="#collapseOneA">Child A</a>
                        </div>
                        <div class="card-body collapse" data-parent="#child1" id="collapseOneA">
                            Crunch wolf moon tempor, sunt aliqua put a bird.
                        </div>
                    </div>
                    <div class="card">
                        <div class="card-header">
                            <a href="#" data-toggle="collapse" data-target="#collapseOneB">Child B</a>
                        </div>
                        <div class="card-body collapse" data-parent="#child1" id="collapseOneB">
                            Another flipp runch wolf moon tempor, sunt aliqua put a bird.
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="card">
            <div class="card-header" id="headingTwo">
                <h5 class="mb-0">
        <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
          Collapsible #2
        </button>
      </h5>
            </div>
            <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordion">
                <div class="card-body">
                    Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird
                    on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table,
                    raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
                </div>
            </div>
        </div>
        <div class="card">
            <div class="card-header" id="headingThree">
                <h5 class="mb-0">
        <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
          Collapsible #3
        </button>
      </h5>
            </div>
            <div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#accordion">
                <div class="card-body">
                    Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird
                    on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table,
                    raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
                </div>
            </div>
        </div>
    </div>
</div>

I am using lists. Should I switch to cards?

I feel the answer is yes as you are trying to achieve an accordion effect.

From the official Bootstrap docs Accordion example:

Using the card component, you can extend the default collapse behavior to create an accordion. To properly achieve the accordion style, be sure to use .accordion as a wrapper.