Angular UI Bootstrap accordion toggle open all

Problem

I'm having an issue with the accordion groups toggle / collapse all.

Expanding collapsing works fine as long as I don't expand /collapse individual accordion groups. I would like the expand, collapse buttons to act as a reset for the accordion groups. That means that regardless of how the individual groups were opened, pressing the collapse / expand all should apply to all groups.

Any suggestions would be most welcomed.

Code:

 <button class="btn btn-default btn-sm" ng-click="expandAll()">Expand all</button>
    <button class="btn btn-default btn-sm" ng-click="collapseAll()">Collapse all</button>

    <accordion close-others="false">
            <accordion-group is-open="firstGroupOpen">
        <accordion-heading>
            <div>
                First
                <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-up': firstGroupOpen, 'glyphicon-chevron-down': !firstGroupOpen}"></i>
            </div>
        </accordion-heading>
        test
        test
    </accordion-group>

    <accordion-group is-open="secondGroupOpen">
        <accordion-heading>
            <div>
                Second
                <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-up': secondGroupOpen, 'glyphicon-chevron-down': !secondGroupOpen}"></i>
            </div>
        </accordion-heading>
        test
        test
    </accordion-group>
</accordion>

Plunker here: Plunk

Problem courtesy of: VictorB

Solution

This happens because of how angular works with watching scope variables. There are multiple fixes for this:

  1. Define a scope object and assign all variables to this object (see example below)
  2. Use the controller as syntax (IMO the best solution)
  3. Use $scope.apply() after updating the variables (this triggers the whole digest of angular, so it might be a heavy operation)

Example of first solution:

$scope.accordion = {
  firstGroupOpen: false,
  secondGroupOpen: false
}

$scope.expandAll = function () {
    $scope.toggleOpen(true);
};

$scope.collapseAll = function () {
    $scope.toggleOpen(false);
};


$scope.toggleOpen = function (openAll) {
    $scope.accordion.firstGroupOpen = openAll;
    $scope.accordion.secondGroupOpen = openAll;
};

See this updated plunker

Solution courtesy of: devqon

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.