How to expand/collapse all rows in Angular - angularjs

I have successfully created a function to toggle the individual rows of my ng-table to open and close using:
TestCase.prototype.toggle = function() {
this.showMe = !this.showMe;
}
and
<tr ng-repeat="row in $data">
<td align="left">
<p ng-click="row.toggle();">{{row.description}}</p>
<div ng-show="row.showMe">
See the plunkr for more code, note the expand/collapse buttons are in the "menu".
However, I can't figure out a way to now toggle ALL of the rows on and off. I want to be able to somehow run a for loop over the rows and then call toggle if needed, however my attempts at doing so have failed. See them below:
TestCase.prototype.expandAllAttemptOne = function() {
for (var row in this) {
if (!row.showMe)
row.showMe = !row.showMe;
}
}
function expandAllAttemptOneTwo(data) {
for (var i in data) {
if (!data[i].showMe)
data[i].showMe = !data[i].showMe;
}
}
Any ideas on how to properly toggle all rows on/off?

Using the ng-show directive in combination with the ng-click and ng-init directives, we can do something like this:
<div ng-controller="TableController">
<button ng-click="setVisible(true)">Show All</button>
<button ng-click="setVisible(false)">Hide All</button>
<ul>
<li ng-repeat="person in persons"
ng-click="person.visible = !person.visible"
ng-show="person.visible">
{{person.name}}
</li>
</ul>
</div>
Our controller might then look like this:
myApp.controller('TableController', function ($scope) {
$scope.persons = [
{ name: "John", visible : true},
{ name: "Jill", visible : true},
{ name: "Sue", visible : true},
{ name: "Jackson", visible : true}
];
$scope.setVisible = function (visible) {
angular.forEach($scope.persons, function (person) {
person.visible = visible;
});
}
});
We are doing a couple things here. First, our controller contains an array of person objects. Each one of these objects has a property named visible. We'll use this to toggle items on and off. Second, we define a function in our controller named setVisible. This takes a boolean value as an argument, and will iterate over the entire persons array and set each person object's visible property to that value.
Now, in our html, we are using three angular directives; ng-click, ng-repeat, and ng-show. It seems like you already kinda know how these work, so I'll just explain what I'm doing with them instead. In our html we use ng-click to set up our click event handler for our "Show All" and "Hide All" buttons. Clicking either of these will cause setVisible to be called with a value of either true or false. This will take care of toggling all of our list items either all on, or all off.
Next, in our ng-repeat directive, we provide an expression for angular to evaluate when a list item is clicked. In this case, we tell angular to toggle person.visible to the opposite value that it is currently. This effectively will hide a list item. And finally, we have our ng-show directive, which is simply used in conjunction with our visible property to determine whether or not to render a particular list item.
Here is a plnkr with a working example: http://plnkr.co/edit/MlxyvfDo0jZVTkK0gman?p=preview
This code is a general example of something you might do, you should be able to expand upon it to fit your particular need. Hope this help!

Related

Angular Add class to ng-repeat element that is updated or added only

Hi I am trying to dynamically add a class to an element that is updated on the view.
http://jsfiddle.net/9s1rfwa8/7/
<div ng-app>
<div ng-controller="TodoCtrl">
<ul>
<li ng-repeat="todo in todos" class="bigfont todo done-{{todo.done}}"> <span>{{todo.text}}</span>
</li>
</ul>
</div>
function TodoCtrl($scope) {
$scope.todos = [{
text: 'learn angular',
done: true
}, {
text: 'build a demo angular appsdfsdfsf',
done: false
}, {
text: 'build an awesome angular app',
done: false
}];
}
How do I add a class to the ng-repeat element that is only changed and not to others.
I am trying to give it a flip effect to the elements that changes.
Ng-repeat will duplicate element that is repeated. If you want to apply class to only one of the element repeated, then you need to add a condition e.g. $index === 0 to ng-class.
ng-class={'first-item-class': $index === 0}
this will apply to the first element only. Use any kind of condition logic to identify its the one you want to apply to.
You can use a custom filter for this, custom filter will be executed whenever there is a change.
For example you can change done property inside your todo object every time user clicks on the row and use the value of todo.done to set class inside your filter
html
<li ng-repeat="todo in todos | filter:handleChange"
class="bigfont todo done-{{todo.done}} {{todo.class}}"
ng-click="todo.done = !todo.done">
<span>{{todo.text}}</span>{{todo.class}}
</li>
js
$scope.handleChange = function(row){
if(!row.done){
row.class = '';
}
else{
row.class = 'changed'
}
return true;
}
this should give you a general idea on how to approach your problem, you can find a working sample in the following plunker.
Demo

How to bind a list of checkboxes in AngularJS

I have a list of checkboxes as following :
<div flex="50" ng-repeat="formationType in formationTypeList">
<md-checkbox class="md-warn md-align-top-left"
value="{{formationType.codeFormation}}"
name="formationSelection[]"
ng-checked="formationSelection.indexOf(formationType) > -1"
ng-click="toggleFormationTypeSelection(formationType)">
{{ formationType.nom }}
</md-checkbox>
</div>
This is the format of formationSelection after I send my form :
formationSelection = [
{
codeFormation: 1,
nom: "ENSA"
},
{
codeFormation: 2,
nom: "CPGE"
}
]
In another scenario I want when I open my form to check the checkboxes which are defined in an array as following :
$scope.formationSelection = res.candidatureProjetProfessionnel.formations;
the object res.candidatureProjetProfessionnel.formations contains this :
formationSelection = [
{
codeFormation: 1,
nom: "ENSA"
},
{
codeFormation: 2,
nom: "CPGE"
}
]
And when I inspect $scope.formationSelection it contains the data I got from res.candidatureProjetProfessionnel.formations :
But I don't know why my checkboxes are not checked even though the $scope.formationSelection is not empty.
How can I solve this ?
i'm not sure what the md-checkbox directive is so i'm just going to use a normal checkbox input. Generally speaking, setting a default value for inputs in angular involves 2 things:
Make sure your inputs have ng-model to store the value of the checkbox and for 2 way data binding (so that you can set it from the controller as well)
In your controller set the variable declared in the ng-model to whatever default value you want.
So in you html:
<input type="checkbox" class="md-warn md-align-top-left" ng-
model="formationSelection[$index]" ng-true-value="{{formationType}}"
name="formationSelection[]">
Make sure you use ng-true-value to declare the value of each checkbox when checked. The ng-model is set to formationSelection[$index] which basically means each checkbox is an item inside the formationSelection array, this way the array will be the collection of the values of all checked inputs.
Now $scope.formationSelection = res.candidatureProjetProfessionnel.formations should work
Here's a working plunker:
http://plnkr.co/edit/sGm39DRWH9EOReiiSrIl?p=preview
You have to use ng-model as shown below.It should be an object like $scope.data = {};.This is just an example where hope you can get the point and work on your scenario. Actually you're having individual check boxes as shown below but values are being set through the loop.So you can apply this concept for your use case as well.Hope this will help to you.
Html
<md-checkbox ng-model="data.cb1" aria-label="Checkbox 1">
Checkbox 1: {{ data.cb1 }}
</md-checkbox>
JS
$scope.data = {};
$scope.data.cb1 = true;
Play with it on Codepen
I think that your method isFormation(formationType) on the directive ng-checked it's not return the result.
In your controller create a function
$scope.isFormation(_type){
return $scope.formationSelection.filter(function(f){return f.nom === _type;}).length > 0;
}

Creating a "Like" button with Angular.js

Im trying to create a like button with Angular.js.
(It is just a heart icon. default color is white = NOT liked. It is red when liked. Like/unlike is toggled by a click)
I get some data from my web service that has also an array of some ID's. These ID's are the ones that clicked the like button before.
Then i populate the DOM with the ng-repeat directive according to the data retrieved from the web service.
I attach the button a ng-class that sets the proper class and a ng-click directive that is supposed to somehow change the class too.
* I cant connect between the ng-class and the ng-click result.
some code:
<div ng-repeat="photo in photos track by photo._id">
<button ng-class="{carouselFooterButtonLikeActive : initLike(photo)}" ng-click="like(photo, this)">
<i class="icon ion-heart"></i>
</button>
</div>
Controller:
// Handle like button click
$scope.like = function(photo, photoScope){
HOW CAN I AFFECT THE NG-CLASS FROM HERE?
}
$scope.initLike = function(photo){
if(photo.likes.indexOf($localstorage.getObject('userInfo').id) > -1) {
$scope.liked = true;
return true;
}
$scope.liked = false;
return false;
}
Edit: added a possible data retrieved from the web service
{
photos: [
{
src: "src1.jpg",
likes:[111,222,333]
},
{
src: "src2.jpg",
likes:[]
}
]
}
You can use as a flag some additional property that will be initially undefined on each photo element - say photo.liked. When user clicks it, $scope.like function sets this property to true. Then ng-class evaluates photo.liked to true and adds carouselFooterButtonLikeActive class to button element.
The code is as follows:
In the template:
<button ng-class="{'carouselFooterButtonLikeActive' : photo.liked}" ng-click="like(photo, this)">
In the controller:
$scope.like = function(photo, photoScope){
photo.liked = true;
}
UPD
Say you have photos array:
[
{'src':'bla-bla.jpg', liked: true, id: 8347},
{'src':'foo-bar.jpg', id: 45},
{'src':'baz-baz.jpg', id: 47}
]
then only the first one will be shown with button.carouselFooterButtonLikeActive class, thanks to ng-class evaluation expression.
UPD2
If photo.likes is an array, you can use:
//template
ng-class="{'carouselFooterButtonLikeActive' : (photo.likes && photo.likes.length >0)}"
//controller
$scope.like = function(photo, photoScope){
photo.likes.push(someUserID);
}

Angular toggling variable within ng-click not working

I have a table that lists customers and for customers that also have a client list allows the user to click the table row to show that list. The HTML looks like this:
<tbody ng-repeat ="item in customers | clientSettingsFilter:customerId">
<tr ng-class="{'row-hover': item.clientSettings.length>0}" ng-click="item.showClients=!item.showClients">
<td><span ng-class="{true:'glyphicon glyphicon-chevron-down', false:'glyphicon glyphicon-chevron-right'}[item.showClients]" ng-hide="item.clientSettings.length==0"></span></td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td><button type="button" class="btn btn-default btn-xs" ng-click="go('/client-config/defaults/'+item.id)">Defaults</button></td>
</tr>
<tr ng-show="item.showClients">
..... // client data
The bizarre behavior I'm having is this:
If I leave the 'showClients' property undefined in the customers data set, everything works as expected, except that the chevron icon does not show at first. After clicking once, it shows up and the toggle works as expected. I was thinking this might be because the ng-class is looking for true or false, and undefined doesn't satisfy either of these.
If I pre-define the showClients property to either true or false, the chevron shows correctly on page load and the client list shows correctly, but the toggle no longer functions, as though ng-click is either not doing anything or for some reason is unable to change the value. I'm not sure how to debug an in-line directive like that.
EDIT
Per request, here is the relevent code from the controller:
filter('clientSettingsFilter', function () {
return function (customers, customerId) {
var filtered = [];
if (!customerId)
return filtered;
customerId = customerId.toLowerCase();
angular.forEach(customers, function (item) {
if (item.id.toLowerCase().indexOf(customerId) !== -1) {
// format some text properties, omitted for brevity
// if this line is uncommented, the ng-click does not work
//item.showClients = false;
filtered.push(item);
}
});
return filtered;
};
});
The conditional you are using in ng-class will only add something when value is either true or false, not when it's undefined.
Instead use the more verbose ternary operator:
ng-class="item.showClients ? 'glyphicon-chevron-down' : 'glyphicon-chevron-right'"
And might as well move the class glyphicon to the ordinary class attribute:
class="glyphicon"
Demo: http://plnkr.co/edit/bxgp4HyFkOygc0foxAKN?p=preview
The behavior you are witnessing when uncommenting item.showClients = false; in your filter is due to how the digest loop works.
If item.showClients is false and you click the tr the following will happen (a bit simplified):
The expression in ng-click will execute, setting item.showClients to true
The digest loop will start
The filter will run and set item.showClients to false again
Filters are meant for filtering, not for modification.
Also note that when using a filter with ng-repeat it will fire each digest cycle, and as each digest loop consists of multiple digest cycles (minimum of two) it's important to keep filters simple or they will have a bad impact on performance.

Change Single Button Color from ngRepeat generated button list

I'm using ngRepeat to generate four buttons. Whenever I click one of the buttons, I want to change its color and also execute a function (for now, I'm just using console.log for sake of simplicity). If I click on another button, I want to change its color while reverting the previous button back to its original color.
I have a couple of issues - the first is that I can't seem to get ng-click to accept two commands (the first being the console.log function and the second being the instruction to change the button color). The other issue is that if I take out the console.log function, I end up changing all of the buttons when I click on one.
Any ideas? Here's the plunkr: http://plnkr.co/edit/x1yLEGNOcBNfVw2BhbWA. You'll see the console.log works but the button changing doesn't work. Am I doing something wrong with this ng-click?
<span class="btn cal-btn btn-default" ng-class="{'activeButton':selectedButt === 'me'}" ng-click="log(element);selectedButt = 'me'" data-ng-repeat="element in array">{{element}}</span>
You can create a simple function in your controller which handles this logic:
$scope.selectButton = function(index) {
$scope.activeBtn = index;
}
Then, you can simply check in your template if the current button is active:
<span class="btn cal-btn btn-default" ng-class="{true:'activeButton'}[activeBtn == $index]" ng-click="selectButton($index);" ng-repeat="element in array">{{element}}</span>
I also changed your plunkr
You may convert your element list from string array to object array first.
$scope.array = [
{"name":"first", "checked":false},
{"name":"second", "checked":false},
{"name":"third", "checked":false},
{"name":"fourth", "checked":false}
];
And your log function need to change to:
$scope.log = function(element) {
console.log(element.name);
angular.forEach($scope.array, function(elem) {
elem.checked = false;
});
element.checked = !element.checked;
}
Then, in your HTML:
<button class="btn cal-btn"
ng-repeat="element in array"
ng-click="log(element)"
ng-class="{activeButton: element.checked, 'btn-default': !element.checked}"
>{{element.name}}</button>
Please see the updated plunker here.

Resources