AngularJS Accordion Expand All Collapse All - angularjs

I am trying to get the accordions to toggle correctly through the directive ng-click. If I have Item one open how do I get it to expand all the accordions? Item two and Item three will continue to expand and collapse but Item one stays stagnant.
Plunker

alternately you can adjust your buttons so that they just loop through the children.
html:
<div ng-controller="AccordionDemo">
<div >
<div class="stuff_in_the_middle" >
<div ng-repeat="m in results" ng-click="m.open = !m.open" style="margin-bottom:20px">
<div heading="{{m.label}}" is-open="m.open" style="background-color:#d2d2d2; cursor:pointer" >
{{m.label}}
</div>
<div ng-show="m.open" style="padding:10px">
contents
</div>
</div>
<span class="btn btn-default" ng-click="toggle(false)">Collapse All</span>
<span class="btn btn-default" ng-click="toggle(true)">Expand All</span>
</div>
<hr />
</div>
</div>
JS:
var module = angular.module('plunker', []);
module.controller('AccordionDemo', ['$scope',
function ($scope) {
$scope.results = [
{label: 'Item 1', open: false},
{label: 'Item 2', open: false},
{label: 'Item 3', open: false}
];
$scope.toggle = function(state) {
$scope.results.forEach(function(e) {
e.open = state;
});
}
}
]);
see it working here: http://plnkr.co/edit/T6iv7mSoat9SQBwSIFJP

You have a problem with scopes. Simple rule is to never set variable value from ng-click or similar directives if you gonna use this variable outside - in parent.
It is caused by ng-repeat, which creates scope and if you will try to define new variable within it(you are doing it, because you have used name plunker, instead of opened), it will be defined only to current item in repeat.
You can use setter function to set it to right scope. So, here we go: http://plnkr.co/edit/h3MtKywiOaIQhpnAzWLT?p=preview

Related

Angular radio buttons - undefined value on check

I have radiobuttons in Angular 1 like this http://jsfiddle.net/md3coyzn/1/ and I need to change value to true / false when radio button is clicked, but I am still getting undefined value, and dont know why
$scope.radioContent = [
{txt: 'One', checked: true},
{txt: 'Two', checked: false}
];
<div ng-repeat="radio in radioContent">
<input type="radio" name="group" ng-model="radio.checked">{{radio.txt}} ---> {{radio.checked}}
</div>
as ng-repeat create its own scope. so you have to access by using $parent
HTML
<div ng-repeat="radio in radioContent track by $index">
<input type="radio" name="group[$index]" ng-model="$parent.selectedRadio" ng-change="$parent.radioChecked()" ng-value="radio" >{{radio.txt}}
</div>
JS
.controller('ExampleCtrl', ['$scope', function ($scope) {
$scope.selectedRadio;
$scope.radioContent = [
{txt: 'One', checked: true},
{txt: 'Two', checked: false}
];
$scope.radioChecked = function () {
console.log('selectedRadio', $scope.selectedRadio);
$scope.selectedRadio.checked = !$scope.selectedRadio.checked
}
}]);
please check the working Fiddle
hope it helps you.
An ng-click method to toggle the value of the radio buttons.
Note that value attribute of the button conflicts with the ng-model attribute so had to remove the later one.
angular.module('ExampleApp', [])
.controller('ExampleCtrl', ['$scope', function ($scope) {
console.clear();
$scope.radioContent = [
{txt: 'One', checked: true},
{txt: 'Two', checked: false}
];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp" ng-controller="ExampleCtrl">
<div ng-repeat="radio in radioContent">
<input type="radio" name="group" value="{{radio.checked}}" ng-click="radio.checked = !radio.checked">{{radio.txt}} ---> {{radio.checked}}
</div>
</div>

AngularJS binding to Bootstrap Popover attribute

I'm trying to dynamically populate the data-title and the data-content of a Bootstrap popover from a JSON create in an AngularJS controller.
Controller Snippet:
$scope.popoverContent = {name: {title: "title", content: "content"}}
HTML Snippet:
<span class="glyphicon glyphicon-question-sign"
aria-hidden="true"
data-toggle="popover"
data-trigger="hover"
data-title="{{popoverContent.name.title}}"
data-placement="right"
data-content="{{popoverContent.name.content}}">
</span>
I'm getting the exact text between the double quotes in the HTML page, {{popoverContent.name.title}}.
I've tried with ng-attr-data-title="{{popoverContent.name.title}}" but in this case, the title does not get displayed at all.
Other variables set in the controller are getting displayed properly in the HTML page.
Is is possible to implement something like this?
Try this code
var demo = angular.module('demo', []);
demo.controller('loadData', function($scope){
$scope.uploadData = function() {
$scope.popoverContent = {name: {title: "title", content: "content"}};
};
});
demo.directive("popUps",function(){
return {
restrict:'E',
replace: true,
transclude: false,
template:'<span class="glyphicon glyphicon-question-sign" aria-hidden="true" data-toggle="popover" data-trigger="hover" data-title="{{popoverContent.name.title}}" data-placement="right" data-content="{{popoverContent.name.content}}">data-title:{{popoverContent.name.title}}</br>data-content:{{popoverContent.name.content}}</span>'
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
<div ng-app='demo'>
<div ng-controller='loadData'>
<button ng-click='uploadData($event)' >show</button>
<div>
<pop-ups></pop-ups>
</div>
</div>
</div>

Changing value of a boolean using ng-click used inside a ng-repeat

I am displaying some data on my html page inside a div using ng-repeat. Inside the div I have a button in order to hide the content of each div seperately.Here is a simplified version of my html file.
<body ng-app="task" ng-controller="repeat">
<div ng-repeat='x in array' ng-show="{{ x.show }}">
<p>{{ x.text }}
</p>
<button ng-click="toggle()">Hide</button>
</div>
</body>
the code in my .js file is as follows
var app = angular.module('task');
app.controller('repeat',function($scope){
$scope.array = [{
show: true,
text:'Sample Text 1'},
{
show: true,
text:'Sample Text 2'},
{
show: true,
text:'Sample Text 3'}];
$scope.toggle = function(){
$scope.array.show = false ;
};
})
Can anyone suggest me the required changes so that on clicking the button inside my div , that particular div gets hidden.
I think I am committing a mistake in referencing the particular element of the array while calling the function toggle() through ng-click
Put your element as an argument in toggle function.
<button ng-click="toggle(x)">Hide</button>
and change it in controller like this:
$scope.toggle = function(x){
x.show = !x.show;
};
And easy to achieve this without calling the function in the controller:
<body ng-app="task" ng-controller="repeat">
<div ng-repeat='x in array' ng-show="showDetail">
<p>{{ x.text }}</p>
<button ng-click="showDetail != showDetail">Hide</button>
</div>
</body>
The method above will also hide the button if you click hide. If you want to hide your content and show it again, the following code can achieve that:
<body ng-app="task" ng-controller="repeat>
<div ng-repeat='x in array'>
<div class="content" ng-show="showContent">
<p>{{ x.text }}</p>
</div>
<div class='btn btn-control'>
<button ng-click="showContent != showContent"> Hide </button>
</div>
</div>
</body>
Well I found a way to actually cater my needs , thank you all for your suggestions. Here is the code I actually used:
<body ng-app="task" ng-controller="repeat">
<div ng-repeat='x in array' ng-hide="x.show">
<p>{{ x.text }}
</p>
<button ng-click="toggle($index)">Hide</button>
</div>
</body>
and in my js file I used it like this:
var app = angular.module('task');
app.controller('repeat',function($scope){
$scope.array = [{
show: true,
text:'Sample Text 1'},
{
show: true,
text:'Sample Text 2'},
{
show: true,
text:'Sample Text 3'}];
$scope.toggle = function(){
$scope.array[index].show = false ;
};
})
In your html pass
<button ng-click="toggle(x.$index)">Hide</button>
While in js
$scope.toggle = function(index){
$scope.array[index].show = !$scope.array[index].show;
};

Parent scope update child scope

I found many ways to update parent scope variable from child scope, which is The Dot, but in my case that didn't help.
I have ui-bootstrap accordion which open and collapse according to isOpen variable which I pass it from the backend.
angular.module('plunker', ['ui.bootstrap']);
function AccordionDemoCtrl($scope) {
$scope.currentPage = 1;
$scope.items = [{
label: 'Item 1',
open: true
}, {
label: 'Item 2',
open: true
}, {
label: 'Item 3',
open: true
}];
$scope.opened = false;
}
<accordion id="accordion_main">
<accordion-group ng-repeat="item in items" heading="{{item.label}}" is-open="item.open">
</accordion-group>
</accordion>
<span class="btn btn-default" id="toggle_all" ng-click="m.open=!m.open">Collapse All</span>
I want to make a collapse all button, which is outside of the scope of ng-repeat. If there is a better way to make a collapse all button please advice,
Change your ngClick to loop through your items and set them to false.
<span class="btn btn-default" id="toggle_all" ng-click="collapseAll()">Collapse All</span>
JS:
$scope.collapseAll = function(){
for(var x = 0; x < $scope.items.length; x++){
$scope.items[x].open = false;
}
};
you can use another var in scope like:
$scope.collapse_all = false;
And in page
<accordion id="accordion_main">
<accordion-group ng-repeat="item in items" heading="{{item.label}}" is-open="!collapse_all && item.open">
</accordion-group>
</accordion>
<span class="btn btn-default" id="toggle_all" ng-click="collapse_all=!collapse_all">Collapse All</span>

angular-ui-bootstrap accordion collapse/expand all

I would like to create a collpase/expand all button for a set of accordions. I am using angular.js v1.2.6 and angular-bootstrap-ui 0.9.0. I haven't been able to find an example of how to do a collpase/expand all. I'm an angular novice and any advice or suggestions is appreciated.
ALSO, I should add that the solution in this post doesn't work in the newer version of angular.js (v1.0.8 vs v1.2.6) that I am using (which is a latest version at the time of this posting). In the newer version it throws an error about trying to create two isolated scopes.
Markup:
<div ng-controller="myCtlr">
<accordion close-others="oneAtATime">
<button class="btn" ng-click="section.isCollapsed = !section.isCollapsed">Toggle Sections</button>
<accordion-group ng-repeat="section in sections" is-open="section.isOpen">
<accordion-heading>
<div class="accordion-heading-content" ng:class="{collapsed: section.isOpen}">
{{section.name}}
</div>
</accordion-heading>
Section content
</accordion-group>
</accordion>
</div>
JS:
var theapp = angular.module('myApp', [
'ui.bootstrap'
])
function myCtlr ($scope) {
$scope.isCollapsed = false;
$scope.sections = [
{'id': '353','otherid': '7','name': 'One','Sequence': '1'},
{'id': '354','otherid': '8','name': 'Two','Sequence': '1'},
{'id': '355','otherid': '9','name': 'Three','Sequence': '1'}
];
}
I've taken Blowsie's plunkr comment and built my own answer that solves the use case that I'm reading into here.
I've moved the close-others attribute to the accordion element where the docs say it goes. I've also added extra buttons to openAll, closeAll or toggleAll.
If you click the header for a single item, only that item opens. If you click a 'All' button, all are affected.
Thanks to Blowsie for the inspiration. I think using the item.open here was the ticket. After that, it's just a matter of affecting all item.open values.
http://plnkr.co/edit/WUKEfcBrSf3XrIQAik67?p=preview
HTML
<div ng-controller="AccordionDemoCtrl">
<accordion close-others="false">
<accordion-group ng-repeat="item in items" is-open="item.open" heading="{{item.name}}">
{{item.open}}
<p>The body of the accordion group grows to fit the contents</p>
</accordion-group>
</accordion>
<button ng-click="openItem(0)">Open 1</button>
<button ng-click="openItem(1)">Open 2</button>
<button ng-click="openItem(2)">Open 3</button>
<button ng-click="openAllItems()">Open All</button>
<button ng-click="closeAllItems()">Close All</button>
<button ng-click="toggleAllItems()">Toggle All</button>
<br/>
{{items |json}}
</div>
JS
angular.module('plunker', ['ui.bootstrap']);
function AccordionDemoCtrl($scope) {
$scope.oneAtATime = true;
$scope.items = [
{name: 'Item 1', open: false},
{name: 'Item 2', open: false},
{name: 'Item 3', open: false}
];
$scope.addItem = function() {
var newItemNo = $scope.items.length + 1;
$scope.items.push('Item ' + newItemNo);
};
$scope.openItem = function(idx) {
console.log(idx);
$scope.items[idx].open = true;
};
$scope.openAllItems = function(){
$scope.items.map(function(item){
item.open = true;
});
};
$scope.closeAllItems = function(){
$scope.items.map(function(item){
item.open = false;
});
}
$scope.toggleAllItems = function(){
$scope.items.map(function(item){
item.open = !item.open;
});
}
}
Here is a method using the is-open attribute.
http://plnkr.co/edit/MliW41xGJAF0Mnw4Rgu7?p=preview

Resources