Reputation: 2313
I am working with ui-bootstrap accordion. I have an accordion inside an accordion.
under the 1st accordion 'Category', I have another accordion, with 3 accordion- group. They are closed by default. I would like this behavior: when you click an accordion group title (say 'fruit'), if all the accordion groups are closed, then it will open them all... but if any groups is open( say if any of the 'fruit', 'meat', and vegetable' is open when user is clicking), then when you click, it will toggle the clicked accordion-group. you can check out the plunker here:
http://plnkr.co/edit/UcETfOVh8RwMX40mOCVv?p=preview
my html and angular code is follow:
<!DOCTYPE html>
<html ng-app="plunker">
<body ng-controller="AccordionDemoCtrl">
<accordion >
<accordion-group>
<accordion-heading> Category</accordion-heading>
<accordion ng-repeat="(category, items) in categories" close-others="oneAtATime" is-open="true">
<accordion-group >
<accordion-heading ><div>{{category}}</div></accordion-heading>
<div ng-repeat="item in items.data">{{item}}</div>
</accordion-group>
</accordion>
</accordion-group>
</accordion>
</body>
</html>
angular.module('plunker', ['ui.bootstrap']);
function AccordionDemoCtrl($scope) {
$scope.categories = {
fruit: {
data: {
apple: 3,
orange: 5,
lemon: 6
},
toggled: false
},
vegetable: {
data: {
lettuce: 1,
broccoli: 5,
spinach: 4
},
toggled: false
},
meat: {
data: {
chicken: 3,
beef: 6,
lamb: 8
},
toggled: false
}
};
}
How can I achieve such behavior? I have work progress in another plunker: http://plnkr.co/edit/9eTfpn81g57Dk4FtVSlA?p=preview I've explored with 'is-open' attribute in accordion, I've tried to refered to the $parent, not producing the behavior i want.
Upvotes: 1
Views: 2083
Reputation: 8970
As mentioned by bobleujr is-open
should work. But the code is a bit tricky and I'm not sure if there is an easier solution.
The problem is that the ng-click
where I'm adding my 'toggleAll' check is called after toggeling the clicked accordion.
So I have to track the previous accordion state to be sure that we have to toggle all accordions. I'm doing this by looping over all accodions states and count if it is open.
Then I can check later if previousCount == 0
and currentCount==1
we need to open all.
I don't like doing two for loops for the behaviour but I think that's the only way to do it.
If it wouldn't toggle the state with ng-click
it would be easier to do. But I don't know how. I've tried to disable the is-open
toggle of the accordion directive but that wasn't working.
Decorating of the accordion directive could help then you could add the check before toggeling. But that's probably not that easy.
Please have a look at the demo below or here in the updated plunkr.
// Code goes here
angular.module('plunker', ['ui.bootstrap'])
.controller('AccordionDemoCtrl', AccordionDemoCtrl);
function AccordionDemoCtrl($scope) {
var prevOpenCount = 0;
$scope.toggle = function(index) {
var openCount = 0,
openAll = false;
// check how many accordions are open
for( var i=0; i < $scope.openState.length; i++ ){
if ($scope.openState[i] === true) {
openCount++;
}
}
if ( openCount === 1 && prevOpenCount === 0) { // open all
for( var i=0; i < $scope.openState.length; i++ ){
$scope.openState[i] = true;
}
}
//console.log(index, $scope.openState, openCount, prevOpenCount);
prevOpenCount = openCount;
};
$scope.categories = {
fruit: {
data: {
apple: 3,
orange: 5,
lemon: 6
},
toggled: false
},
vegetable: {
data: {
lettuce: 1,
broccoli: 5,
spinach: 4
},
toggled: false
},
meat: {
data: {
chicken: 3,
beef: 6,
lamb: 8
},
toggled: false
}
};
$scope.openState = new Array(Object.keys($scope.categories).length);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.js"></script>
<!--<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.9.0.js"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular-animate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.3/ui-bootstrap-tpls.js"></script>
<!--<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
--><script src="script.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<div ng-app="plunker" ng-controller="AccordionDemoCtrl">
<accordion>
<accordion-group>
<accordion-heading> Category</accordion-heading>
<accordion ng-repeat="(category, items) in categories" close-others="oneAtATime">
<accordion-group ng-click="toggle($index, $event)" is-open="openState[$index]">
<accordion-heading ><div><!--{{openState}}-->{{category}}</div></accordion-heading>
<div ng-repeat="item in items.data">{{item}}</div>
</accordion-group>
</accordion>
</accordion-group>
</accordion>
</div>
Upvotes: 3
Reputation: 1176
WABBIT0111
you may want to use the attribute is-open=ctrlVar
.
This way you will be able to set it with a ng-click=action to change ctrlVar state
and then toggle them back to original position.
Upvotes: 1