How to calculate a value using checkbox AngularJs in a repeater - javascript

I use a ngRepeat with a checkbox and need when I check each item compute the value total of selected items as below:
HTML:
<tr ng-repeat="ciclo in ciclos">
<td><input id="idCiclo" type="checkbox" ng-click="computeTotal(ciclo)">
</td>
<td>{{ciclo.Quantity}}</td>
<td>{{ciclo.Value | currency}}</td>
...
<tfoot>
<tr>
...
<td>{{TotalQuantity}}</td>...
Controller:
$scope.computeTotal = function (ciclo) {
$scope.TotalQuantity += ciclo.Quantity; //Here I need Add or Subtract a value
};

You should have a property that indicates whether a checkbox has been checked or unchecked so that you can decide to add or subtract.
You would be using ngModel with ngChange (ngClick is usually better for elements that don't have built-in click expectations/behaviors).
Example:
View:
<tr ng-repeat="ciclo in ciclos">
<td>
<input class="ciclo" type="checkbox" ng-model="ciclo.checked" ng-change="computeTotal(ciclo)">
<!-- Note that I took out the ID. IDs should never be used in ngRepeat,
as it heavily risks multiple elements having the same ID,
which should ALWAYS be unique.
A class works much better for collections like this. -->
</td>
<td>{{ciclo.Quantity}}</td>
<td>{{ciclo.Value | currency}}</td>
</tr>
Controller:
$scope.computeTotal = function (ciclo) {
if(ciclo.checked)
$scope.TotalQuantity += ciclo.Quantity;
else
$scope.TotalQuantity -= ciclo.Quantity;
};

Related

Angular.Js dynamically updating an input with sum of other 3 inputs

I have a table with 6 rows and 4 columns (the fourth one is a Total: which should be a sum of the above 3 columns). Basically what I want to do is calculate the sum of each column and show the total number in the fourth column. My table is generated using ng-repeat.
Something like:
<table>
<thead>
<tr>
<th ng-repeat="item in items">{{item}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>Input1:</td>
<td ng-repeat="collection in collections">
<input type="text" ng-model="collection.row1">
</td>
</tr>
<tr>
<td>Input2:</td>
<td ng-repeat="collection in collections">
<input type="text" ng-model="collection.row2">
</td>
</tr>
<tr>
<td>Input3:</td>
<td ng-repeat="collection in collections">
<input type="text" ng-model="collection.row3">
</td>
</tr>
<tr>
<td>Sum:</td>
<td ng-repeat="collection in collections" ng-model="collection.total">
{{collection.total}}
</td>
</tr>
</tbody>
</table>
"collections" from ng-repeat would be an array with 6 objects which I'm getting from an API using a GET method and storing my data in a $scope.
"Total" row with ng-model is coming from backend with the calculus already done but I need a way to show it on client as it is updating dynamically.
I've tried $watch and $watchCollection and also ng-change but I can't find a way to make it work. In my controller I used a for to go through my array of objects and tried to sum every [i] position but that didn't work.
Is there another solution for my issue?
Here is what I tried in my controller:
$scope.collections = [];
$scope.getTotal = function(){
var total = 0;
for(var i = 0; i < $scope.collections[i].length; i++){
var myItems= $scope.collections[i];
total = (myItems.row1+ myItems.row2+ myItems.row3);
}
return total;
};
Thank you.
Why not simply do it in the template?
<td>{{collection.row1 + collection.row2 + collection.row3}}</td>
Also, there should not be an ng-model unless it is an <input>. That's probably where your main error is. Ng-model will try to set the value inside the <td>'s, and so the angular template ({{X}}) and ng-model are competing for the display value inside the <td></td> in your code given
If you calculate the total in the back-end
$scope.CalculatedTotal = Some Value;
so you can call in the last row:
<td>Sum:</td>
<td ng-repeat="collection in collections" ng-model="collection.total">
{{CalculatedTotal}}
</td>
or store the CalculatedTotal in to the object
currentCollection.Total = CalculatedTotal;
something like that

AngularJs: uncheck checkbox after item is removed

after spending a lot of time on this simple issue and having made a lot of research, I was wondering if someone could give me some help.
I have data which is generated inside of a table like so:
<tbody>
<tr class="odd gradeX" ng-repeat="user in ctrl.datas | orderBy:ctrl.sortType:ctrl.sortTypeReverse">
<td>
<input type="checkbox" class="checkboxes" value="{{user.id}}" ng-click="ctrl.addItem(user)"/>
</td>
<td>
{{user.given_name}}
</td>
<td>
{{user.family_name}}
</td>
<td>
{{user.email}}
</td>
<td class="center" ng-bind-html="ctrl.convertToDate(user.created_at) | date: 'dd-MMMM-yyyy hh:mm'"></td>
<td>
<span class="btn blue-hoki"> Details </span>
</td>
</tr>
</tbody>
Above is a container where I get the items selected via a checkbox, add the in an array and give the user the ability to delete the selected item:
<tr ng-repeat="user in ctrl.checkedObject track by $index" ng-show="user.id">
<td>{{user.family_name}}</td>
<td>{{user.given_name}}</td>
<td>
<button class="btn blue" ng-click="ctrl.removeItem($index)">Unselect</button>
</td>
</tr>
In my controller, here are the two functions used to do so:
this.checkedObject = [];
//Add selected user
this.addItem = function (user) {
self.checkedObject.push(user);
};
this.removeItem = function(obj){
delete self.checkedObject[obj];
};
What i'd like to achieve is to uncheck the corresponding checkbox if a user changes his selection.
The thing is, I have no idea how to target the corresponding checkbox. Does anyone have a clue?
Thanks in advance
Try ng-checked like:
<input type="checkbox" ng-checked="user !== null" class="checkboxes" value="{{user.id}}" ng-click="ctrl.addItem(user)"/>
And set the item (user) to null on button click (inside removeItem() ) or a other variable.
I set up a simple plunker to show one approach, which would be to assign a selected property to each user when his/her checkbox is checked, and set an ng-checked attribute on the checkbox corresponding to user.selected (so will be unchecked when false).
Using this approach you won't need to push and delete from the array of checkedUsers, you can just filter all the users by whether they are selected or not.
function getSelected() {
ctrl.checkedObject = _.filter(ctrl.datas, {selected: true});
}
ctrl.selectUser = function (user) {
user.selected = true;
getSelected();
};
ctrl.removeUser = function(user){
user.selected = false;
getSelected();
};

AngularJS, easy way to show a delete button when a checkbox is checked in the list of users under ng-repeat

I am trying to toggle a delete button which has already a function bound to it. The list is created with ng-repeat checking the users object. But the methds I have seen so far are either simple model show which does not work in my case. Or complex directive controller methods.
All I need is to check whether at least one checkbox is checked. Here is the snippet from the code:
<table class="table">
<tr ng-repeat="user in ctrl.commonUserService.users | filter:ctrl.commonUserService.suppressLoggedOnUserFilter()">
<td><input type="checkbox" ng-model="user.selected" value="y" /></td>
<td title="User Name"><strong>{{user.userName}}</strong></td>
How can I easily do this with Angular? I tried to create a function looping users and looking if they are selected at all but don't think I can put this function to ng-show.
You'll have to check if at least one box is selected when the state changes:
<td><input type="checkbox" ng-model="user.selected" ng-change="ctrl.userSelected()" value="y" /></td> <!-- use ng-change to notify when a checkbox is clicked -->
<button ng-click="ctrl.delete()" ng-show="ctrl.usersSelected">Delete</button> <!-- if ctrl.usersSelected is true show delete -->
In the controller:
this.userSelected = function userSelected() { // when checkbox is clicked check users to see if at least one is selected and save the state in this.userSelected
this.usersSelected = this.commonUserService.users.some(function(user) {
return user.selected;
});
};
You can do this fairly easily using the ng-change directive on your inputs. See this plunkr for the working example, but it basically goes like this:
View:
<table class="table">
<tr ng-repeat="user in users">
<td><input type="checkbox" ng-change="isSelected()" ng-model="user.selected" /></td>
<td title="User Name"><strong>{{user.userName}}</strong></td>
</tr>
</table>
<button class="delete" ng-show="showDelete">Delete</button>
Controller:
$scope.isSelected = function() {
var somethingSelected = false;
$scope.users.forEach(function(user, index) {
if (user.selected) somethingSelected = true;
});
$scope.showDelete = somethingSelected;
};

Using angularjs expression to check boxes

reading on ng-checked attribute I realize we can use angular expressions to determine wether a checkbox is checked or not.
I have images and dates. I want to make a table representing which image is active at a specific date. this sql fiddle should help you understand what I mean.
In the fiddle, the four checkboxes are checked, but one of them (the one corresponding to the first image and the 'feb' date) should not be checked, since 'feb' is not in the dates of the first image (see the $scope definition below)
My problem is that the expression date = image.dates in the ng-checked attribute always return true, hence the four checked checkboxes.
What expression could I use to verify that a specific date is in the image's defined dates?
I can change the data model, so if it would be easier to have the dates of a specific image as an array rather than a string please go ahead.
view
<div ng-controller="MyCtrl">
<table>
<tr>
<td style="width:80px;"></td>
<td style="width:35px;" ng-repeat="date in dates">{{date}}</td>
</tr>
<tr ng-repeat="image in images">
<td>{{image.name}}</td>
<td ng-repeat="date in dates">
<input ng-checked="date = image.dates" type="checkbox" />
</td>
</tr>
</table>
</div>
app
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.images = [
{name:'Image 1',dates:'jan'},
{name:'Image 2',dates:'jan,feb'}
];
$scope.dates = [
"jan",
"feb"
];
}
You will have to check if the dates contains the date expression.
Something like this:
<tr ng-repeat="image in images">
<td>{{image.name}}</td>
<td ng-repeat="date in dates">
<input ng-checked="image.dates.indexOf(date) > -1" type="checkbox" />
</td>
</tr>

Select closest control element regardless of type (Input, Select etc.) for Validation

Let me explain:
I have a table form and some fields are required and I am trying to create custom validation.
example:
<table>
<tr>
<td class="required">Description</td>
<td>
<input id="input1" />
</td>
<td>Phone</td>
<td>
<input id="input2" />
</td>
</tr>
<tr>
<td class="required">Location</td>
<td>
<select id="select1"/>
</td>
<td>Email</td>
<td>
<input id="input3"/>
</td>
</tr>
</table>
What I wanna do is find all elements with class required
which is pretty easy using:
var requiredElements = document.querySelectorAll(".required");
And then I want to find their closest control element and check if it's value is empty. The problem is I don't know if it's gonna be input or select. I was thinking of using the .closest() function but it could lead to unwanted results if two different inputs are equally close to a required (like in the example above).
Any help would be much appreciated.
You can select a control regardless of type with jQuery by using any one of a number of selectors and combining it with one or more additional selectors.
In the code snippet you provide, the controls you want to select (input1 and select1) are child elements of a table cell element that is a sibling of the cell with the class "required", so we can build a selection thus:
$(".required + td").child
which breaks down as:
Find the elements with the "required" class applied to them.
This will give us the 2 table cells:
<td class="required">Description</td>
and
<td class="required">Location</td>
For each element returned by 1. use the "next adjacent" selector + with td to get the next table cell:
<td><input id="input1" /></td>
and
<td><select id="select1" /></td>
For each element returned by 2. get the child element:
<input id="input1" />
and
<select id="select1" />
There is also a jsFiddle to illustrate actions on the targets (change border to dark red).
Edit
This works because the layout in your snippet consistently places the elements you want to target in the same position relative to the element with your selection criteria. You must have some consistent way of finding elements that are not marked with a class/id otherwise you can't achieve your objective.
Although I like Raad's answer I'd like to post this answer to say what I did to solve my problem.
First of all I added a custom attribute labelFor to every label td with value equal to the id of it's corresponding input as follows:
<table>
<tr>
<td class="required" labelFor="input1">Description</td>
<td>
<input id="input1" />
</td>
<td labelFor="input2">Phone</td>
<td>
<input id="input2" />
</td>
</tr>
<tr>
<td class="required" labelFor="select1">Location</td>
<td>
<select id="select1"/>
</td>
<td labelFor="input3">Email</td>
<td>
<input id="input3"/>
</td>
</tr>
</table>
Then I used the following Validation function:
function validateForm () {
var self = this;
var validationPassed = true;
//First I will gather every .required element in an Array
var requiredTags = document.querySelectorAll(".required");
//Then I will loop through the array
for (var i = 0; i < requiredTags.length; i++) {
//Get value of attribute "labelFor" which would be the controlId that this label refers to
var controlId = $(requiredTags[i]).attr("labelFor");
//Then I use this to check if that control's value is empty.
if ($("#" + controlId).val() == ('' || null)) {
validationPassed = false;
}
}
if (!validationPassed) {
alert("Please fill all the required fields");
}
return validationPassed;
}
This way I check if all required fields are not empty and return true, or return false and an alert to warn user.
I find that the problem Raad described in his Edit is the main reason why this approach could be more useful. You don't have to worry if your input element is always in the same position relatively to your label td element.

Categories

Resources