daniel
daniel

Reputation: 120

Bootstrap collapse one after another

I despair on the collapse feature from bootstrap.

I have for instance three buttons. Those three buttons collapse different content in the same target box.

When I push the first button, the div #one collapses. When I push another button, div #one should first toggle back, or close and only when it's closed the other box is allowed to collapse.

Simply said: One target area for the collapsing content, one open collapse box at a time.

<button class="toggler" data-toggle="collapse" data-target="#one">One</button>
<button class="toggler" data-toggle="collapse" data-target="#two">Two</button>
<button class="toggler" data-toggle="collapse" data-target="#thr">Two</button>

...

<div class="here-is-only-space-for-one-at-a-time">
  <div class="collapse" id="one">
    <h1>I was triggered by the first button</h1>
  </div>
  <div class="collapse" id="two">
    <h1>I was triggered by the second button</h1>
  </div>
  <div class="collapse" id="thr">
    <h1>I was triggered by the third button</h1>
  </div>
</div>

I know that there are events with callbacks like

$(element).on("hidden.bs.collapse, callback);

but I don't get the flash of insight.

Upvotes: 1

Views: 2530

Answers (2)

Travis Acton
Travis Acton

Reputation: 4430

What you would need to do is to give each of your hideable divs a shared class name and also give them their own unique ID

  <div  class="col-md-4 col-sm-4" >
   <div id="one" class="hideMeBox">
    <img  src="http://www.starwarscats.com/wp-content/uploads/2013/02/storm-trooper-cats.jpg" style="max-width: 150px;"/>
  </div>
 </div>
 <div  class="col-md-4 col-sm-4">
  <div id="two" class="hideMeBox">
   <img  src="http://www.starwarscats.com/wp-content/uploads/2013/01/cat-costume-darth-vader.jpg" style="max-width: 150px;"/>
  </div>
 </div>
 <div  class="col-md-4 col-sm-4">
  <div id="three" class="hideMeBox">
   <img src="https://futureofstarwars.files.wordpress.com/2014/09/cat-helpmeobiwan.jpg" style="max-width: 150px;"/>
  </div>
</div>

Define your buttons for control:

<div class="btn btn-large btn-info" id="hideOne">One</div>
<div class="btn btn-large btn-warning" id="hideTwo">Two</div>
<div class="btn btn-large btn-danger" id="hideThree">Three</div>

In Jquery, bind to your button clicks and insert your hide/show options

$('#hideOne').click(function() {
 $.when($('.hideMeBox').not($("#one")).slideDown("slow")).done(function() { $( "#one" ).slideToggle( "slow"); });
});

$('#hideTwo').click(function() {
 $.when($('.hideMeBox').not($("#two")).slideDown("slow")).done(function() { $( "#two" ).slideToggle( "slow"); });
});

$('#hideThree').click(function() {
  $.when($('.hideMeBox').not($("#three")).slideDown("slow")).done(function() { $( "#three" ).slideToggle( "slow"); });
});

What you are effectively doing here is on button click, issue a jquery show animation (slideDown) on every class with the exception of the element that contains the ID. Then issue a toggle animation on your target div. You won't have to check/track the status of show/hide as jQuery will just auto toggle whatever state it is currently in.

Here is the catch:

When you need to execute animations such as this on multiple elements (call animations by class instead of single ID) then what it does is put them in the queue.

If you tried to use the normal complete callback on the animation such as

$( ".whatever" ).slideDown( "slow", function() {
// Animation complete.
});

It would call the animation complete function every time an animation in the queue is completed.

In comes deferred objects to save the day. In this specific case you should look at jQuery.when()

https://api.jquery.com/jquery.when/

Per the API documentation:

In the case where multiple Deferred objects are passed to jQuery.when(), the method returns the Promise from a new "master" Deferred object that tracks the aggregate state of all the Deferred it has been passed. The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected. If the master Deferred is resolved, the doneCallbacks for the master Deferred are executed. The arguments passed to the doneCallbacks provide the resolved values for each of the Deferreds, and match the order in the Deferreds that were passed to jQuery.when()

working example here: https://jsfiddle.net/qs4v999p/9/

Upvotes: 2

Mjbain10
Mjbain10

Reputation: 189

Check out this codepen. It doesn't use any callback functions, just native Bootstrap class name for collapsible. Is this kind of what you're trying to do? Where you can have both collapsible elements open at once instead of an accordian effect?

HTML

<div class="container">
  <a href="#demo" class="btn btn-info" data-toggle="collapse">Simple collapsible</a>
  <div id="demo" class="collapse">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit
  </div>

  <br>

  <a href="#demo2" class="btn btn-info" data-toggle="collapse">Another collapsible</a>
  <div id="demo2" class="collapse">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit
  </div>
</div>

Upvotes: 0

Related Questions