I'm having a hard time counting selected checkboxes in my application. I've tried following along some other stack overflow questions but no dice yet...if you guys have any experience with counting checkboxes, some help would be great.
HTML:
<div class="row">
<div class="col-md-12">
<table id="document-table" st-table="documents" st-safe-src="yourDisplayedCollection" class="table">
<div>Total checked: ({{selectedCounter}})</div>
<thead>
<tr>
<th>
<st-select-all all="yourDisplayedCollection"></st-select-all>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="document in documents">
<td><input type="checkbox" ng-model="document.isSelected"/></td>
</tr>
</tbody>
</table>
</div>
</div>
Controller:
.controller('DocumentsController', /** #ngInject */ function ($scope, restData, dateFormats, documents) {
$scope.dateFormat = dateFormats.angularDateFilter;
$scope.documents = documents.resultBag[0].documentBag;
$scope.yourDisplayedCollection = [].concat(documents.resultBag[0].documentBag);
$scope.selectAll = function (selected) {
var documents = $scope.documents;
angular.forEach(documents, function (documents) {
documents.selected = selected;
});
// Update the counter
if(selected){
$scope.selectedCounter = documents.length;
} else {
$scope.selectedCounter = 0;
}
};
EDIT:
I have a check all boxes checkbox at the top which is why i have the yourDisplayedCollection in the table as well as the ng-model="document.isSelected"
You need to rework a couple things if I am understanding the anticipated outcome correctly.
First(html):
<tr ng-repeat="document in documents">
//Bind your model directily to the selected property in your object (document)
<td><input type="checkbox" ng-model="document.selected"/></td>
</tr>
Second:
$scope.selectAll = function (selected) {
var documents = $scope.documents;
angular.forEach(documents, function (doc) {
if(doc.selected)
$scope.selectedCounter +=1;
});
};
This will give you a correct count everytime. Though your function naming is misleading. SelectAll should mean literally select all. To me it looks like your just counting.
Simplest way to do this is use Array.prototype.filter() and use length of filtered array
<input type="checkbox" ng-model="document.selected"/>
And for counter:
$scope.selectedCounter = $scope.documents.filter(function(item){
return item.selected;
}).length;
Need to be aware that you are breaking the golden rule of always using an object in ng-model.
ng-repeat creates a child scope and when you use a primitive in the child scope the parent controller can't see it change
Related
First of all I am very new in Angular JS.
I have a list of items and by clicking on each one, it should be added to the table. The items are stored in a json file.
If the click event repeated several times the counter input which is located on the table must increases.
<ul class="list-inline" >
<li ng-repeat="food in foods" class="food_list">
<img class="img-box" src="images/{{ food.food_photo }}" ng-click = 'addRow(food)'><br/><span>{{food.food_name}}</span>
</li>
</ul>
<table class="table" id="table-right">
<tr>
<th>Item Name</th>
<th>Quantity</th>
<th>Price</th>
<th class="hidden-print">Delete</th>
</tr>
<tr ng-repeat="row in rows">
<td>{{row.food_name}}</td>
<td><input type="number" class="form-control" ng-model="row.food_count"></td>
<td>{{row.food_cost}}</td>
<td class="hidden-print"><button class="btn btn-info hidden-print" data-ng-click="removeRow($index)">Remove</button></td>
</tr>
app = angular.module('app',[]);
app.controller('MyCtrl', ['$scope','$http', function($scope, $http){
$scope.rows = [];
$scope.addRow = function(obj) {
$scope.foodname = obj.id;
$scope.foodprice = obj.price;
$scope.rows.push(obj);
$scope.counter++;
}
}]);
Could you please help me? Thank You.
First you have to understand that food_count property of a row object is the variable that should be updated on repetitive clicks. Updating any other $scope variables won't change row specific data because your view is bound to $scope.rows object.
Your addRow function should look like this.
$scope.addRow = function(obj) {
if($scope.rows.indexOf(obj) >= 0){ // if this obj already exist
$scope.rows[$scope.rows.indexOf(obj)].food_count++;
}
else
$scope.rows.push(obj);
}
Then the objects of $scope.foods should have a property called food_count to display.
$scope.foods = [
{food_name:'Jani',food_cost:'10', food_count:0},
{food_name:'Hege',food_cost:'8',food_count:0},
{food_name:'Kai',food_cost:'5',food_count:0}]
solution
I am displaying some data in a web app that I am getting from a SQL database using a http service. I want to be able to modify the information of that data on the same table where the data is shown. I am using angularjs and I am using the directives ng-show and ng-hide on the table. Here I show the part of the code I am talking about.
<table>
<tr>
<td><font size = 4>Servicio: </font> </td>
<td> </td>
<td>
<select class="col-sm-12" name="repeatSelect" id="repeatSelect" ng-model="currentItem.ServicioId">
<option ng-repeat="option in items.Servicio" value="{{option.Id}}"> {{option.Nombre}}</option>
</select>
</td>
</tr>
</table>
<h4>Cliente: {{getNameC(currentItem.ServicioId)}}</h4>
<br />
<button class="btn btn-primary" ng-click="editOrCreate()">Nuevo</button>
<button class="btn btn-primary" ng-click="list()">Actualizar</button>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Cantidad</th>
<th>Tipo Concepto</th>
<th>Descripción</th>
<th>Precio Unitario</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in itemsSC">
<td>
<div ng-hide="editingData[item.Id]">{{item.Cantidad}}</div>
<div ng-show="editingData[item.Id]"><input ng-model="currentItem.Cantidad" /></div>
</td>
<td>
<div ng-hide="editingData[item.Id]">{{getName(item.ServicioConceptoTipoId)}}</div>
<div ng-show="editingData[item.Id]">
<select name="repeatSelect" id="repeatSelect" ng-model="currentItem.ServicioConceptoTipoId">
<option ng-repeat="option in items.ServicioConceptoTipo" value="{{option.Id}}"> {{option.Nombre}}</option>
</select>
</div>
</td>
<td>
<div ng-hide="editingData[item.Id]">{{item.Descripcion}}</div>
<div ng-show="editingData[item.Id]"><input type="text" ng-model="currentItem.Descripcion" /></div>
</td>
<td>
<div ng-hide="editingData[item.Id]">{{item.PrecioUnitario}}</div>
<div ng-show="editingData[item.Id]"><input ng-model="currentItem.PrecioUnitario" /></div>
</td>
<td>
<button class="btn btn-xs btn-primary" ng-hide="editingData[item.Id]" ng-click="editOrCreate(item)">Modificar</button>
<button class="btn btn-xs btn-primary" ng-show="editingData[item.Id]" ng-click="saveEdit(currentItem,0)">Actualizar</button>
<button class="btn btn-xs btn-primary" ng-hide="viewField" ng-click="delete(item)">Eliminar</button>
</td>
</tr>
</tbody>
<tfoot id="total">
<tr>
<td colspan="3" class="text-right">Total:</td>
<td class="text-right">
{{total(currentItem.ServicioId) | currency}}
</td>
</tr>
</tfoot>
</table>
On my controller I am using object arrays to get the information from the databases and I am using a mirror array to keep the boolean values of the data shown on the table, so depending on the boolean value the tables shows the data or get an input for the user to modify the data.
I get the mirror array once I know the service and client related to the data I want to show and which is possible to be modified.
However, when I click on the button to modify the status of the ng-hide or ng-show object named editingData, the controllers modifies it, but the $digest run all the other functions related to the bindings of the view and returns the bool object array to its inital values.
I haven´t been able to find away to go around this normal working way of the $digest and $watches so my $editingData object is not modified to its initial values. Here I show the code of the controller related to this.
angular.module("App")
.controller("ConceptoCtrl", function ($scope, $http, $resource, serviciosConceptoFactory, serviciosConceptoTipoFactory, serviciosFactory, clientesFactory) {
$scope.list = function () {
$scope.items = serviciosConceptoFactory.query();
$scope.itemsT = serviciosConceptoTipoFactory.query();
$scope.items.ServicioConceptoTipo = $scope.itemsT;
$scope.itemsS = serviciosFactory.query();
$scope.items.Servicio = $scope.itemsS;
$scope.itemsC = clientesFactory.query();
$scope.itemsS.Cliente = $scope.itemsC;
}
//some other functions
$scope.editingData = {};
$scope.getitemsSC = function (item) {
$scope.itemsSC = [];
for (var j = 0; j < $scope.items.length; j++) {
if ($scope.items[j].ServicioId == item) {
newitem = $scope.items[j];
$scope.itemsSC.push(newitem);
}
}
for (var i = 0; i < $scope.itemsSC.length; i++) {
$scope.editingData[$scope.itemsSC[i].Id] = false;
}
}
$scope.editOrCreate = function (item) {
$scope.currentItem = item;
$scope.editingData[item.Id] = true;
}
$scope.list();
});
The {{getNameC(currentItem.ServicioId}} function shown on the html file is the one that calls the $scope.getItemsSC(item) function once it knows the services and client related to the data that will be shown and it is this function the one that initializes the boolean values for the $scope.editingData mirror array depending on the Id of the item.
The $scope.editOrCreate(item) function is the one that changes the boolean object of the specified item so that the view shows the input element for the user instead of the data. However, $digest re-runs the $scope.getItemsSC(item) function because the $watches were modified, and that´s what I want to avoid, because in this case the input elements are never shown.
I thank in advance any help provided
Instead of using the HTML to call functions when data is a available, use the $promise property attached to the resources.
$scope.list = function () {
$scope.items = serviciosConceptoFactory.query();
$scope.itemsT = serviciosConceptoTipoFactory.query();
$scope.items.ServicioConceptoTipo = $scope.itemsT;
$scope.itemsS = serviciosFactory.query();
$scope.items.Servicio = $scope.itemsS;
$scope.itemsC = clientesFactory.query();
$scope.itemsS.Cliente = $scope.itemsC;
var promiseArray = [$scope.items.$promise,
$scope.itemsT.$promise,
$scope.itemsS.$promise,
$scope.itemsC.$promise
];
$q.all(promiseArray).then(function(resultsArray) {
var items = resultsArray[0];
var itemsT = resultsArray[1];
var itemsS = resultsArray[2];
var itemsC = resultsAttay[3];
//create mirror array here
//create editingData array here
});
};
By using the .then method of the promises, the processing of the data can be delayed until it arrives from the server. This way there is no need for the HTML to call functions.
I downloaded an Angular demo app to learn and work my way through Angular basics. I am having issue with applying a filter and sort to a data table. I made it by referring some examples and not sure if it is correct.
My table is :
<div class="widget-content" ng-controller="getAllBenchersController">
<table ng-table="talentPoolList" show-filter="true" class="table table-striped table-bordered">
<tr ng-repeat="employee in data | filter: testFilter">
<td data-title="'#'">{{$index + 1}}</td>
<td data-title="'Employee ID'" sortable="'empno'" filter="{ 'empno': 'text' }">
{{employee.employee.employeeNo}}
</td>
<td data-title="'First Name'" sortable="'employee.employee.firstName'" filter="{ 'employee.employee.firstName': 'text' }">
{{employee.employee.firstName}}
</td>
</tr>
</table>
</div>
Controller :
myApp.controller('getAllBenchersController', ['$scope', 'employeeTalentPoolServices', function ($scope, employeeTalentPoolServices) {
employeeTalentPoolServices.getAllBenchers().then(function (result) {
$scope.data = result.data;
$scope.testFilter = function (item) {
return (item.state.state.toLowerCase() === 'available' || item.state.state.toLowerCase() === 'blocked');
}
});
I have no clue how it works. Can anyone explain and provide a solution to fix this issue?
Thanks in advance
So to explain your demo example I've created a similar example to make you understand what's happening in your question.
We have a employees data with different statuses so when I want to display the list of employees I just want show 'fair' and 'good' so I've written a filter function passed to filter directive to tell what items should be displayed from the list.
If you observe the function it takes every item from list and checks for status to match the desired statuses for displaying.
Check out the demo for the same, hope this gives you a clear understanding on what's happening in your Demo app.
var app = angular.module('app',[]);
app.controller('getAllBenchersController',function($scope,$filter){
$scope.data = {employee:[
{'no':1,'name':'max','status':'bad'},
{'no':2,'name':'fox','status':'good'},
{'no':3,'name':'juno','status':'bad'},
{'no':4,'name':'pet','status':'fair'},
{'no':5,'name':'xyz','status':'good'},
{'no':6,'name':'shit','status':'bad'},
{'no':7,'name':'doggy','status':'fair'},
{'no':8,'name':'hmmm','status':'bad'}
]}
//this test filter is a function which allows me to decide which data should be displayed in this case I've used 'fair' & 'good' status employees to be displayed...
$scope.testFilter = function (item) {
return (item.status.toLowerCase() === 'good' || item.status.toLowerCase() === 'fair');
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" class="widget-content" ng-controller="getAllBenchersController">
<table>
<tr ng-repeat="emp in data.employee | filter: testFilter">
<td>{{$index+1}} </td>
<td> {{emp.no}}</td>
<td>{{emp.name}} </td>
</tr>
</table>
</div>
I have an array within my scope called checkedInChildren. The array contains just string values. I want a table to repeat for each string in the checkedInChildren array. Here is what I have so far:
<div ng-app="MyApp" ng-controller="myCtrl">
<div>
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="child in checkedInChildren">
<td>test</td>
</tr>
</tbody>
</table>
</div>
</div>
Here is my controller:
app.controller("myCtrl", function($scope, $http) {
$scope.checkedInChildren = [];
$scope.addChildToCheckedIn = function(childName) {
$scope.checkedInChildren.push(childName);
}
});
No rows show no matter what names I add to that array. I omitted some code in the controller and some of the HTML, but I am debugging and clearly seeing values in the array. Any ideas?
You have to add {{child}} to bind each item to the view.
<tr ng-repeat="child in checkedInChildren">
<td>
{{child}}
</td>
</tr>
on your HTML you're referencing a different controller, put the proper name
<div ng-app="MyApp" ng-controller="checkInCtrl">...</div>
Demo
Working Plnkr
It is not displaying test because there is no item in your checkedInChildren array.
From Angular Doc:
The ngRepeat directive instantiates a template once per item from a
collection.
$scope.checkedInChildren = [];
$scope.addChildToCheckedIn = function (childName) {
$scope.checkedInChildren.push(childName);
}
$scope.addChildToCheckedIn('John');
You did not call addChildToCheckedIn method, that is why checkedInChildren array is empty.
hope that solve your problem.
Did you call the addChildToCheckedIn function? Try this. Hope this helps.
I have a table that has a list from database with checkbox on each row, checkbox will used for ex. during deletion of the record.
So what i am trying to achieve is that when i clicked the delete button, angular will loop each row in table and check the checkbox whether is checked, if yes the please proceed to delete. Dont have any idea how to do this. Someone please give some related example.
Here is my code
index.html
<button class="ui red labeled icon button right floated" type="button" data-content="Delete selected item(s)" id="delete" ng-click="deleteSeleted()"><i class="trash icon"></i>Delete</button>
<div class='container-table'>
<table class="ui fixed single line celled table striped sortable compact" style="width:2000px" id="mytable">
<thead>
<tr>
<th class="width-checkbox"><input type="checkbox" ng-model="matin.selectedAll" /></th>
<th class="width-120">Item</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-checked="matin.selectedAll"></td>
<td>{{x.item}}</td>
</tr>
</tbody>
</table>
</div>
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-model="x.selected"></td>
<td>{{x.item}}</td>
</tr>
Angular Js Code
for (var k = 0; k < $scope.data.length; k++)
{
if($scope.data[k].selected==true)
{
//Perform your desired thing over here
var val=$scope.data[k].item //to getData
}
}
Please find the fiddler link which i have created to select all the items in the table and on delete print which ever is checked https://jsfiddle.net/dfL1L944/3/
var appModule = angular.module('Module', []);
appModule.controller("DataController", function($scope) {
$scope.data = [{"name":"Alex"},{"name":"Juni"}]
$scope.deleteAll = false;
$scope.deleteSeleted = function(){
$scope.data.forEach(function(x) {
console.log(x.name);
});
}
$scope.selectedAll = function(){
$scope.data.forEach(function(x) {
if($scope.deleteAll){
x.deleted = true;
}
else{
x.deleted = false;
}
});
}
});
HTML Code
<div ng-app="Module"> <div ng-controller="DataController">
<button class="ui red labeled icon button right floated" type="button" data-content="Delete selected item(s)" id="delete" ng-click="deleteSeleted()"> <i class="trash icon"></i>Delete</button> <div class='container-table'> <table class="ui fixed single line celled table striped sortable compact" style="width:200px" id="mytable"> <thead>
<tr>
<th width="20px">
<input type="checkbox" ng-model="deleteAll" ng-click="selectedAll()" /></th>
<th>Item</th>
</tr> </thead> <tbody>
<tr ng-repeat="x in data">
<td width="2px"><input type="checkbox" ng-checked="x.deleted"></td>
<td>{{x.name}}</td>
</tr> </tbody> </table> </div>
</div> </div>
You could use $filter (you would need to insert $filter as a dependency)
$scope.data: [ // assuming your model looks like this
{
Id: "my_id",
Name: "my_name",
checked: true
}
];
var myFilteredValues = $filter('filter')($scope.data, { $: true });
And in your HTML
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-model="x.checked"></td>
<td>{{x.Name}}</td>
</tr>
You can add a .toDelete property to every x in your data array, for example, and bind the checkboxes like this:
<input type="checkbox" ng-model="x.toDelete">
Afterwards you can create a button under the table:
<input type="button" ng-click="deleteRows();" value="Delete rows">
...And then create a function on your controller's scope (a newbie-friendly function):
$scope.deleteRows = function(){
var i=0;
for(i=0; i<data.length; i++){
if(data[i].toDelete){
//send your server requests here and do
//your stuff with the element if needed
data.splice(i, 1); //remove the element from the array
i--; //decrement the value of i so it stays the same
//(array is now shorter than it used to be)
}
}
}
You can also keep the information on what row is to be deleted in a separate array on the same scope but this solution seems simpler to me.
Regarding the "Check All" checkbox at the top, you can create a function and bind it with ng-click to a button or any other element and use that function to simply iterate through all the elements and set the .toDelete property to true for each one of them.