17

I have a problem with bootstrap 3 collapse, after opening a panel programmatically it is possible to keep another panel open while reopening the first panel.

My HTML:

<button type="button" class="btn showpanel">Show panel 3</button>
<button type="button" class="btn hidepanel">Hide panel 3</button>
<button type="button" class="btn openpanel">Open panel 3</button>
<button type="button" class="btn closepanel">Close panel 3</button>
<hr/>
<div class="panel-group" id="accordion">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#panel1">Panel 1</a>
            </h4>
        </div>
        <div id="panel1" class="panel-collapse collapse">
            <div class="panel-body">
                Contents panel 1
            </div>
        </div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#panel2">Panel 2</a>
            </h4>
        </div>
        <div id="panel2" class="panel-collapse collapse">
            <div class="panel-body">
                Contents panel 2
            </div>
        </div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#panel3">Panel 3</a>
            </h4>
        </div>
        <div id="panel3" class="panel-collapse collapse">
            <div class="panel-body">
                Contents panel 3
            </div>
        </div>
    </div>
</div>

And some JavaScript:

$(".hidepanel").on("click", function() {
    $("#panel3").parent().hide();
});
$(".showpanel").on("click", function() {
    $("#panel3").parent().show();
});
$(".openpanel").on("click", function() {
    $("#panel3").collapse('show');
});
$(".closepanel").on("click", function() {
    $("#panel3").collapse('hide');
});

My jsfiddle that demonstrates this issue

To reproduce:

  1. Click the button 'Open panel 3'.
  2. Click 'Panel 2' to open it. So far no problems.
  3. Click 'Panel 3' to open it again. Panel 2 remains open!

So opening a panel programmatically seems to mess up bootstraps internal registration about panel states? I don't see anything visibly wrong with the 'state change' of the third panel (it's class changes from 'collapse' to 'in' and back as you would expect).

KyleMit
  • 45,382
  • 53
  • 367
  • 544
Moolie
  • 539
  • 1
  • 7
  • 16

3 Answers3

28

You can create a handler for the collapse show event which occurs just before any panels are displayed.

Add this to ensure any other open panels are closed before the selected one is shown:

$('#accordion').on('show.bs.collapse', function () {
    $('#accordion .in').collapse('hide');
});

Bootply demo

You can read more about the collapse events here: http://getbootstrap.com/javascript/#collapse

Zim
  • 296,800
  • 77
  • 616
  • 554
  • This certainly works, but I wonder if this is a known bootstrap bug that we are working around here. I'm gonna check the buglist. – Moolie Oct 03 '13 at 12:18
  • 1
    I don't think it's a bug. Your buttons are 'manually' controlling the accordions usual open/close behavior which may be the desired behavior in some cases. – Zim Oct 03 '13 at 12:22
  • 2
    If I understand the collapse widget well, my html is supposed to make the accordion to act as 'one panel open at max' because of the data-parent attribute I used, you can also create a 'multiple open panel' accordion by using the data-target attribute (for example see http://plnkr.co/edit/OxbVII?p=preview). So I think if I manually open or close a panel, the accordion should follow this principle. – Moolie Oct 03 '13 at 12:51
  • 1
    The problem with this approach is that when you have nested accordions and have this handler on the outer accordion, it still gets fired from event on the inner accordion. – ProfNimrod Jan 18 '15 at 14:23
2

I think the problem is due to the way you are changing the open panel. Rather than using the 'show' feature you need to fire the click event on the appropriate panel link. For example with an accordion with an id "accordion", with three panels, if you want to show the 2 panel then use:

$("a[href=#accordion-2]").click()

Or whatever ID you have given your second panel (I use twitterboostrapmvc so the panel ids are auto-generated from the accordion ID).

ProfNimrod
  • 3,722
  • 1
  • 26
  • 44
  • This is also the workaround recommended in the bootstrap github issue for this behaviour https://github.com/twbs/bootstrap/issues/9933 – Tim Nov 23 '17 at 12:38
0

For anyone using data-target attributes to control the accordion (rather than the href attribute), this is an adaptation of ProfNimrod's answer which will click the relevant element if the target is currently hidden. (Note that the if check relies on setting up the accordion with the collapsed class applied by default, which I find useful anyway to take advantage of using css to put a chevron icon on the accordions).

var expandAccordion = function() {
    var header = $('[data-target="#accordion-0"]');
    if (header.hasClass('collapsed')) {
        header.click();
    }
}
Tim
  • 4,170
  • 4
  • 32
  • 50