3

I have 4 expandable menus and 5 buttons. Collapse first button expands/closes the first menu, Collapse second button expands/closes the second menu and so on.

As it is: Button Collapse all for each menu closes it if it is expanded and expands it if it is closed.

Want to be: Whereas I want my Collapse all button to expand all menus if they are closed and don't change them if they are expanded. And then if clicked again closes all the menus that are expanded and don't change the closed menus. Here is a fiddle I wrote for As it is: expand menu fidlle

.row {
  background: #f8f9fa;
  margin-top: 20px;
}

.col {
  border: solid 1px #6c757d;
  padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.css" rel="stylesheet"/>

<p>
  <button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample1, #collapseExample2, #collapseExample3, #collapseExample4" aria-expanded="false" aria-controls="collapseExample">
    Collapse all
  </button>
   <button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample1" aria-expanded="false" aria-controls="collapseExample">
    Collapse first
  </button>
  <button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample2" aria-expanded="false" aria-controls="collapseExample">
    Collapse second
  </button>
  <button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample3" aria-expanded="false" aria-controls="collapseExample">
    Collapse third
  </button>
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample4" aria-expanded="false" aria-controls="collapseExample">
    Collapse fourth
  </button>
</p>
<div class="collapse" id="collapseExample1">
  <div class="card card-body">
    hi first
  </div>
</div>
<div class="collapse" id="collapseExample2">
  <div class="card card-body">
    hi second
  </div>
</div>
<div class="collapse" id="collapseExample3">
  <div class="card card-body">
    hi third
  </div>
</div>
<div class="collapse" id="collapseExample4">
  <div class="card card-body">
    hi fourth
  </div>
</div>

How can I do it?

vrintle
  • 5,501
  • 2
  • 16
  • 46
seyet
  • 1,080
  • 4
  • 23
  • 42

3 Answers3

5

A naive solution I can think of now is to bind the collapse all click event via a custom handler that shows or hides all collapsibles based on a state on the collapse all button, instead of via Bootstrap built-in data-toggle="collapse" and data-target="*".

<p>
    <button id="toggle-all" class="btn btn-primary" type="button">
        Collapse all
    </button>
    <button class="btn btn-primary" type="button" data-toggle="collapse" ... />
    ...
</p>
<div class="collapse" />
...

Then in this Collapse all's button click event, you can have a state on this button itself (via data-) to memorize whether to show or hide all collapsibles. And based on that state variable, you can call either .collapse('show') or .collapse('hide') on all collapsibles manually.

The show method won't show a collapsible again if it's already shown. And the hide method won't hide a collapsible if it's already hidden.

$(function() {
    $('#toggle-all').click(function() {
        // Declare a variable, `data-to-show`, to contain the state whether to show/hide
        // all collapsibles.
        // It defaults to true, which means it's about to show all.
        if (!$(this).data('to-show')) {
            $(this).data('to-show', true);
        } else {
            $(this).data('to-show', !$(this).data('to-show'));
        }
        
        if ($(this).data('to-show')) {
            $('.collapse').collapse('show');
        } else {
            $('.collapse').collapse('hide');
        }
        return false;
    });
});

enter image description here


demo: https://jsfiddle.net/davidliang2008/cvy2kbpz/28/


Another better "solution" I can think of is to declare an extra data attribute, maybe something like data-toggle-all-at-the-same-time="true", and override Bootstrap's built-in .collapse() so that when it sees that data attribute being true, it doesn't toggle the target elements which are already toggled?

Sadly I haven't found an easy way to do so, yet.

David Liang
  • 20,385
  • 6
  • 44
  • 70
0

I would use the toggle function from jQuery. Here is a link to its docs https://api.jquery.com/toggle/

This function hides an element if it is beign shown; or shows it if it is hidden. Simple and works like a charm without many checks.

Sergio A.
  • 342
  • 2
  • 13
-3
  • You need to include jQuery onto your html page. Right at the bottom. Let this script be the last element within your body tag.
  • Then you will need to include all the javascript files that come within the boostrap folder (if you have downloaded the folder).

Add the following tags on your script. As mentioned, right before the tag

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>