Twitter bootstrap collapse: change display of toggle button

做~自己de王妃 提交于 2019-11-28 17:23:37

try this. http://jsfiddle.net/fVpkm/

Html:-

<div class="row-fluid summary">
    <div class="span11">
        <h2>MyHeading</h2>  
    </div>
    <div class="span1">
        <button class="btn btn-success" data-toggle="collapse" data-target="#intro">+</button>
    </div>
</div>
<div class="row-fluid summary">
    <div id="intro" class="collapse"> 
        Here comes the text...
    </div>
</div>

JS:-

$('button').click(function(){ //you can give id or class name here for $('button')
    $(this).text(function(i,old){
        return old=='+' ?  '-' : '+';
    });
});

Update With pure Css, pseudo elements

http://jsfiddle.net/r4Bdz/

Supported Browsers

button.btn.collapsed:before
{
    content:'+' ;
    display:block;
    width:15px;
}
button.btn:before
{
    content:'-' ;
    display:block;
    width:15px;
}

Update 2 With pure Javascript

http://jsfiddle.net/WteTy/

function handleClick()
{
    this.value = (this.value == '+' ? '-' : '+');
}
document.getElementById('collapsible').onclick=handleClick;

Here's another CSS only solution that works with any HTML layout.

It works with any element you need to switch. Whatever your toggle layout is you just put it inside a couple of elements with the if-collapsed and if-not-collapsed classes inside the toggle element.

The only catch is that you have to make sure you put the desired initial state of the toggle. If it's initially closed, then put a collapsed class on the toggle.

It also requires the :not selector, so it doesn't work on IE8.

HTML example:

<a class="btn btn-primary collapsed" data-toggle="collapse" href="#collapseExample">
  <!--You can put any valid html inside these!-->
  <span class="if-collapsed">Open</span>
  <span class="if-not-collapsed">Close</span>
</a>
<div class="collapse" id="collapseExample">
  <div class="well">
    ...
  </div>
</div>

Less version:

[data-toggle="collapse"] {
    &.collapsed .if-not-collapsed {
         display: none;
    }
    &:not(.collapsed) .if-collapsed {
         display: none;
    }
}

CSS version:

[data-toggle="collapse"].collapsed .if-not-collapsed {
  display: none;
}
[data-toggle="collapse"]:not(.collapsed) .if-collapsed {
  display: none;
}

JS Fiddle

All the other solutions posted here cause the toggle to get out of sync if it is double clicked. The following solution uses the events provided by the Bootstrap framework, and the toggle always matches the state of the collapsible element:

HTML:

<div class="row-fluid summary">
    <div class="span11">
        <h2>MyHeading</h2>  
    </div>
    <div class="span1">
        <button id="intro-switch" class="btn btn-success" data-toggle="collapse" data-target="#intro">+</button>
    </div>
</div>
<div class="row-fluid summary">
    <div id="intro" class="collapse"> 
        Here comes the text...
    </div>
</div>

JS:

$('#intro').on('show', function() {
  $('#intro-switch').html('-')
})
$('#intro').on('hide', function() {
  $('#intro-switch').html('+')
})

That should work for most cases.

However, I also ran into an additional problem when trying to nest one collapsible element and its toggle switch inside another collapsible element. With the above code, when I click the nested toggle to hide the nested collapsible element, the toggle for the parent element also changes. It may be a bug in Bootstrap. I found a solution that seems to work: I added a "collapsed" class to the toggle switches (Bootstrap adds this when the collapsible element is hidden but they don't start out with it), then added that to the jQuery selector for the hide function:

http://jsfiddle.net/fVpkm/87/

HTML:

<div class="row-fluid summary">
    <div class="span11">
        <h2>MyHeading</h2>  
    </div>
    <div class="span1">
        <button id="intro-switch" class="btn btn-success collapsed" data-toggle="collapse" data-target="#intro">+</button>
    </div>
</div>
<div class="row-fluid summary">
    <div id="intro" class="collapse"> 
        Here comes the text...<br>
        <a id="details-switch" class="collapsed" data-toggle="collapse" href="#details">Show details</a>
        <div id="details" class="collapse">
            More details...
        </div>
    </div>
</div>

JS:

$('#intro').on('show', function() {
    $('#intro-switch').html('-')
})
$('#intro').on('hide', function() {
    $('#intro-switch.collapsed').html('+')
})

$('#details').on('show', function() {
    $('#details-switch').html('Hide details')
})
$('#details').on('hide', function() {
    $('#details-switch.collapsed').html('Show details')
})

Add some jquery code, you need jquery to do this :

<script>
        $(".btn[data-toggle='collapse']").click(function() {
            if ($(this).text() == '+') {
                $(this).text('-');
            } else {
                $(this).text('+');
            }
        });
        </script>

My following JS solution is better than the other approaches here because it ensures that it will always say 'open' when the target is closed, and vice versa.

HTML:

<a href="#collapseExample" class="btn btn-primary" data-toggle="collapse" data-toggle-secondary="Close">
    Open
</a>
<div class="collapse" id="collapseExample">
  <div class="well">
    ...
  </div>
</div>

JS:

$('[data-toggle-secondary]').each(function() {
    var $toggle = $(this);
    var originalText = $toggle.text();
    var secondaryText = $toggle.data('toggle-secondary');
    var $target = $($toggle.attr('href'));

    $target.on('show.bs.collapse hide.bs.collapse', function() {
        if ($toggle.text() == originalText) {
            $toggle.text(secondaryText);
        } else {
            $toggle.text(originalText);
        }
    });
});

Examples:

$('[data-toggle-secondary]').each(function() {
    var $toggle = $(this);
    var originalText = $toggle.text();
    var secondaryText = $toggle.data('toggle-secondary');
    var $target = $($toggle.attr('href'));

    $target.on('show.bs.collapse hide.bs.collapse', function() {
        if ($toggle.text() == originalText) {
            $toggle.text(secondaryText);
        } else {
            $toggle.text(originalText);
        }
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"/>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>

<a href="#collapseExample" class="btn btn-primary" data-toggle="collapse" data-toggle-secondary="Close">
    Open
</a>
<div class="collapse" id="collapseExample">
  <div class="well">
    ...
  </div>
</div>

JS Fiddle

Other benefits of this approach:

  • the code is DRY and reusable
  • each collapse button stays separate
  • you only need to put one change into the HTML: adding the data-toggle-secondary attribute

I guess you could look inside your downloaded code where exactly there is a + sign (but this might not be very easy).

What I'd do? I'd find the class/id of the DOM elements that contain the + sign (suppose it's ".collapsible", and with Javascript (actually jQuery):

<script>
     $(document).ready(function() {
         var content=$(".collapsible").html().replace("+", "-");
         $(".collapsible").html(content));
     });
</script>

edit Alright... Sorry I haven't looked at the bootstrap code... but I guess it works with something like slideToggle, or slideDown and slideUp... Imagine it's a slideToggle for the elements of class .collapsible, which reveal contents of some .info elements. Then:

         $(".collapsible").click(function() { 
             var content=$(".collapsible").html();
             if $(this).next().css("display") === "none") { 
                 $(".collapsible").html(content.replace("+", "-"));
             }
             else $(".collapsible").html(content.replace("-", "+"));
         });

This seems like the opposite thing to do, but since the actual animation runs in parallel, you will check css before animation, and that's why you need to check if it's visible (which will mean it will be hidden once the animation is complete) and then set the corresponding + or -.

Bruno A.

I liked the CSS-only solution from PSL, but in my case I needed to include some HTML in the button, and the content CSS property is showing the raw HTML with tags in this case.

In case that could help someone else, I've forked his fiddle to cover my use case: http://jsfiddle.net/brunoalla/99j11h40/2/

HTML:

<div class="row-fluid summary">
    <div class="span11">
        <h2>MyHeading</h2>  
    </div>
    <div class="span1">
        <button class="btn btn-success collapsed" data-toggle="collapse" data-target="#intro">
            <span class="show-ctrl">
                <i class="fa fa-chevron-down"></i> Expand
            </span>
            <span class="hide-ctrl">
                <i class="fa fa-chevron-up"></i> Collapse
            </span>            
        </button>
    </div>
</div>
<div class="row-fluid summary">
    <div id="intro" class="collapse"> 
        Here comes the text...
    </div>
</div>

CSS:

button.btn .show-ctrl{
    display: none;
}
button.btn .hide-ctrl{
    display: block;
}
button.btn.collapsed .show-ctrl{
    display: block;
}
button.btn.collapsed .hide-ctrl{
    display: none;
}

Easier with inline coding

<button type="button" ng-click="showmore = (showmore !=null && showmore) ? false : true;" class="btn float-right" data-toggle="collapse" data-target="#moreoptions">
            <span class="glyphicon" ng-class="showmore ? 'glyphicon-collapse-up': 'glyphicon-collapse-down'"></span>
            {{ showmore !=null && showmore ? "Hide More Options" : "Show More Options" }}
        </button>


<div id="moreoptions" class="collapse">Your Panel</div>

Some may take issue with changing the Bootstrap js (and perhaps validly so) but here is a two line approach to achieving this.

In bootstrap.js, look for the Collapse.prototype.show function and modify the this.$trigger call to add the html change as follows:

this.$trigger
  .removeClass('collapsed')
  .attr('aria-expanded', true)
  .html('Collapse')

Likewise in the Collapse.prototype.hide function change it to

this.$trigger
  .addClass('collapsed')
  .attr('aria-expanded', false)
  .html('Expand')

This will toggle the text between "Collapse" when everything is expanded and "Expand" when everything is collapsed.

Two lines. Done.

EDIT: longterm this won't work. bootstrap.js is part of a Nuget package so I don't think it was propogating my change to the server. As mentioned previously, not best practice anyway to edit bootstrap.js, so I implemented PSL's solution which worked great. Nonetheless, my solution will work locally if you need something quick just to try it out.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!