Toggling accordion panel icons with ng-class and ng-click
Asked Answered
F

7

10

I have an accordion with "chevron" icons that are toggled to point up or down when clicked, this is done with ng-click and ng-class. The accordion only permits one panel to be open at the same time - so when I click on a panel that is closed, the panel that is open closes. But how do I toggle the chevron icon on the open panel that is getting closed with ng-click?

Originally i could do it with DOM manipulation etc, but since this is a partial view in angular I cannot do it.

Code:

<div class="panel-group" id="accordion">
  <div class="panel panel-default">
    <div class="panel-heading">
      <h4 class="panel-title">
        <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" ng-click="firstpaneisopen=!firstpaneisopen">
           <i class="glyphicon" ng-class="{'glyphicon-chevron-up': firstpaneisopen, 'glyphicon-chevron-down': !firstpaneisopen}"></i> Collapsible Group Item #1
         </a>
      </h4>
     </div>
    <div id="collapseOne" class="panel-collapse collapse in">
     <div class="panel-body">
       Body
     </div>
    </div>
  </div>
  <div class="panel panel-default">
   <div class="panel-heading">
     <h4 class="panel-title">
       <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" ng-click="secondpaneisopen=!secondpaneisopen>
         <i class="glyphicon" ng-class="{'glyphicon-chevron-up': secondpaneisopen, 'glyphicon-chevron-down': !secondpaneisopen}"></i> Collapsible Group Item #2
       </a>
     </h4>
    </div>
    <div id="collapseTwo" class="panel-collapse collapse">
     <div class="panel-body">
       Body
     </div>
    </div>
   </div>
 </div>
Flutist answered 6/8, 2014 at 12:43 Comment(0)
T
3

I would recommend that you check out 'UI Bootstrap' from the AngularUI team. It's a collection of "Bootstrap components written in pure AngularJS".

http://angular-ui.github.io/bootstrap/

Their website features an example which shows their Accordion directive using ng-class to toggle the chevron icons.

http://angular-ui.github.io/bootstrap/#/accordion

Their directive also features a close-others attribute which, if true, will ensure only a single panel is open at any one time.

<accordion close-others="true">
Taranto answered 10/8, 2014 at 15:5 Comment(1)
This led me to an equivalent for us Foundation users as well.Aletheaalethia
H
4

This is what I've tried and it seems to work

In my controller I have

$scope.menuStatus = [   { isOpen : true     },
                        { isOpen : false    }, 
                        { isOpen : false    } ]

In my html I have

<accordion id='cntLeftMenu' close-others='false'>
    <accordion-group is-open='menuStatus[0].isOpen'>
        <accordion-heading class='menu-title'>
            Cars <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': menuStatus[0].isOpen , 'glyphicon-chevron-right': !menuStatus[0].isOpen }"></i> 
        </accordion-heading>
        <ul class='left-menu'>
            <li><a href=''>test1</a></li>
            <li><a href=''>test1</a></li>
            <li><a href=''>test1</a></li>
        </ul>

    </accordion-group>

    <accordion-group is-open='menuStatus[1].isOpen'>
        <accordion-heading class='menu-title'>
            Customers <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': menuStatus[1].isOpen , 'glyphicon-chevron-right': !menuStatus[1].isOpen }"></i> 
        </accordion-heading>
        <ul class='left-menu'>
            <li><a href=''>test1</a></li>
            <li><a href=''>test1</a></li>
            <li><a href=''>test1</a></li>
        </ul>

    </accordion-group>

    <accordion-group is-open='menuStatus[2].isOpen'>
        <accordion-heading class='menu-title'>
            Staff <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': menuStatus[2].isOpen , 'glyphicon-chevron-right': !menuStatus[2].isOpen }"></i> 
        </accordion-heading>
        <ul class='left-menu'>
            <li><a href=''>test1</a></li>
            <li><a href=''>test1</a></li>
            <li><a href=''>test1</a></li>
        </ul>

    </accordion-group>


<accordion>
Higley answered 7/11, 2014 at 3:50 Comment(0)
P
4

How about working with CSS? Bootstrap adds a class collapsed on the html element that has the data-toggle="collapse". When the slide opens, it removes this collapsed class. We can then work with css to, for example, rotate the span element (a child of the element that has the data-toggle attribute).

<style>

 button.collapsed span {
  transform: rotate(-90deg);
 }
</style>
<button type="button" class="btn btn-info collapsed" data-toggle="collapse" data-target="#demo">
 Simple collapsible
 <span class="glyphicon glyphicon-chevron-down"></span>
</button>
<div id="demo" class="collapse">
 Lorem ipsum dolor...
</div>

IMPORTANT NOTE : Ensure collapsed class is added to the element that has the data-toggle="collapse" attribute for this to work smoothly. Otherwise, on initial loading of the element, the span element doesn't rotate as expected the first time.

Perilune answered 23/4, 2016 at 8:16 Comment(2)
Its good trick without creating new variables. But only problem I face is, it delays rendering so [] shows before it displays glyphicon.Retardation
@Aamol, you have to ensure the bootstrap.css is loaded in the <head> tag and the <script> tags should be placed just before the closing body tag - </body>. This will ensure glyphicons are available when the page is loaded. May be also explore ng-cloak and https://mcmap.net/q/280422/-angularjs-hide-content-until-dom-loaded...Perilune
T
3

I would recommend that you check out 'UI Bootstrap' from the AngularUI team. It's a collection of "Bootstrap components written in pure AngularJS".

http://angular-ui.github.io/bootstrap/

Their website features an example which shows their Accordion directive using ng-class to toggle the chevron icons.

http://angular-ui.github.io/bootstrap/#/accordion

Their directive also features a close-others attribute which, if true, will ensure only a single panel is open at any one time.

<accordion close-others="true">
Taranto answered 10/8, 2014 at 15:5 Comment(1)
This led me to an equivalent for us Foundation users as well.Aletheaalethia
D
3

The easiest solution I have ever think. And not to use any controller,

<div 
  class="fa fa-fw list-arrow" 
  ng-class="{'fa-angle-down': isClicked, 'fa-angle-right' : !isClicked}" 
  ng-click="isClicked = !isClicked">
</div>

You can write similar like me.

Dishearten answered 4/8, 2016 at 8:46 Comment(0)
A
2

Did some researching, I was able to use this method to add the class open to the panel-header when it's toggled open. This is example allows multiple panels to be open and uses Angular Strap Collapse.

Template:

<div class="panel-group" 
     role="tablist" 
     data-ng-model="multiplePanels.activePanels" 
     data-allow-multiple="true" 
     data-bs-collapse>
   <div class="panel panel-default" ng-repeat="location in locations">
       <div class="panel-heading" 
            role="tab" 
            data-ng-class="{'open' : multiplePanels.activePanels.indexOf($index) > -1}"
            bs-collapse-toggle>
            <h3>Some Header Stuff</h3>
       </div>
       <div class="panel-collapse" role="tabpanel" bs-collapse-target>
            <div class="panel-body">
                <p>Stuff in the panel body...</p>
            </div>
       </div>
   </div>
</div>

JS in the controller:

$scope.multiplePanels.activePanels = [];
Aymara answered 26/4, 2015 at 19:4 Comment(0)
E
1

You can use bootstrap (tested in 4+) collapse and the following styles to toggle the button;

<style>
    [id^='particon'] {
      display: block !important;
    }

    [id^='particon']:after {
      font-family: 'Glyphicons Halflings';
      color: grey;
    }

    [id^='particon'].collapse:after {
      content: "\e081";
    }

    [id^='particon'].collapse.show:after {
      content: "\e082";
    }

    /*optional*/
    [id^='particon'].collapsing {
      transition: none;
    }
</style>

For fully working snipplet;

https://js.do/code/changecollapseicon

Elysium answered 3/2, 2019 at 18:59 Comment(0)
F
0

After some research i've got one way to solve this.

JS:

$scope.firstpaneisopen = false;
$scope.secondpaneisopen = false;

Modified ng-click on the first pane:

<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" ng-click="firstpaneisopen=!firstpaneisopen; secondpaneisopen=false">

vice versa on the second pane.

I don't think this is any elegant solution, especially if we got more than two panes, but it works.

Flutist answered 6/8, 2014 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.