How to call ng-disabled with a function from web service response - angularjs

The ng-disabled has a function that takes the response from api and two parameters. But it never gets called after the response.
function PermissionController(permissionResource) {
var vm = this;
vm.message = 'Permission';
vm.permissions;
permissionResource.query(function(data) {
vm.permissions = data;
});
vm.isPermissionMissing = function (r, a) {
for(var i = 0; i < vm.permissions.length; i++) {
if(vm.permissions[i].Resource == r && vm.permissions[i].Action == a)
return -1;
}
return 1;
};
}
module.controller("PermissionController", PermissionController);
Then my view has a button to show/hide with ng-disabled.
<button type="submit" class="btn btn-primary btn-block" ng-disabled="isPermissionMissing('account', 'search')">Search</button>
Then a table with ng-repeat
<table class="table">
<thead>
<tr>
<td>resource</td>
<td>action</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="permission in vm.permissions">
<td>{{ permission.Resource }}</td>
<td>{{ permission.Action }}</td>
</tr>
</tbody>
</table>
Problem is by the time the page loads with the api response, it does not call the function in ng-disabled.
I tried the promise then with no luck.
permissionResource.query(function(data) {
vm.permissions = data;
}).$promise
.then(function (result) {
vm.isPermissionMissing = function (r, a) {
for(var i = 0; i < result.length; i++) {
if(result[i].Resource == r && result[i].Action == a)
return -1;
}
return 1;
};
});

The angular documentation shows ngInit being used with ngDisabled.
https://docs.angularjs.org/api/ng/directive/ngDisabled
In your instance I would move the function call to ng-init. Then in the function you need to create a scope variable to set true/false. Let me know if that works for you.
<button type="submit" class="btn btn-primary btn-block" ng-init="isPermissionMissing('account', 'search')" ng-disabled="{{isDisabled}}">Search</button>
vm.isPermissionMissing = function (r, a) {
for(var i = 0; i < vm.permissions.length; i++) {
if(vm.permissions[i].Resource == r && vm.permissions[i].Action == a)
vm.isDisabled = false;
}
vm.isDisabled = true;
};enter code here

Related

Push and splice into array when checkall and checkbox is checked in angularjs

I am trying to push and splice the elements based on checkall, single checkbox clicked, my problem is I am getting a list from angularjs post request and displayed it using ng-repeat I have given provision to enter some text in a new column along with ng-repeat data. Now based on the user selection of checkall or single checkbox clicked I am pushing the data into array. Here I am able to push the data when the user clicked on single checkbox, but when the user clicked on chekall checkbox 0, 1 are pushing the array instead of textbox value. Any help will be greatly appreciated.
Html
<table class='reportstd' align='center' width='80%'>
<tr class='trdesign'>
<td>
<input type="checkbox" name="checkAll" id="all" data-ng-model="checkedAll" data-ng-change="toggleCheckAll()" />
</td>
<td> Sl No</td>
<td> RO No.</td>
<td> Truck No.</td>
</tr>
<tr data-ng-repeat="user in RosList">
<td> <input type="checkbox" value="{{user.do_ro_no}}" data-ng-model="user.checked" data-ng-change="modifyArrayToPost(user,truck_no[$index])" /> </td>
<td>{{$index + 1}}</td>
<td>{{user.do_ro_no}}</td>
<td><input type='text' data-ng-model="truck_no[$index]" id="truck_no_{{$index}}" name="truck_no_{{$index}}" value=""></td>
</tr>
</table>
<table>
<tr>
<td colspan='2'><input type="submit" id="btn_submit" name='sea' value='Search' data-ng-submit="postROs(arrayToPost)" /></td>
</tr>
</table>
Angularjs
$scope.arrayToPost = [];
$scope.toggleCheckAll = function() {
if ($scope.checkedAll) {
angular.forEach($scope.RosList, function(user, truckno) {
user.checked = true;
$scope.modifyArrayToPost(user, truckno);
});
} else {
angular.forEach($scope.RosList, function(user, truckno) {
user.checked = false;
$scope.modifyArrayToPost(user, truckno);
});
}
}
$scope.modifyArrayToPost = function(user, truckno) {
if (user.checked && truckno != null && $scope.arrayToPost.indexOf(user.do_ro_no) == -1) {
$scope.arrayToPost.push(user.do_ro_no, truckno);
} else if (!user.checked) {
$scope.arrayToPost.splice($scope.arrayToPost.indexOf(user.do_ro_no, truckno), 2);
}
}
$scope.$watch('RosList', function() {
var allSet = true;
var allClear = true;
angular.forEach($scope.RosList, function(user, truckno) {
if (user.checked) {
allClear = false;
} else {
allSet = false;
}
});
var checkAll = $element.find('#all');
checkAll.prop('indeterminate', false);
if (allSet) {
$scope.checkedAll = true;
} else if (allClear) {
$scope.checkedAll = false;
} else {
$scope.checkedAll = false;
checkAll.prop('indeterminate', true);
}
}, true);
$scope.RosList = [
{do_ro_no: "217PALV000201898", slno: 1, },
{do_ro_no: "317PALV000201898", slno: 2, }
]
truck_no model is not coming from RosList.
You should initialize truck_no in your controller as $scope.truck_no = [] in order to access the values, and in your $scope.toggleCheckAll function change $scope.modifyArrayToPost(user, truckno); to $scope.modifyArrayToPost(user, $scope.truck_no[truckno]);
EDIT:
I've slightly modified your code to handle all cases.
Demo: https://next.plnkr.co/edit/DnzsCFkPQU8ByFZ8
If I understand the issue correctly, I think that the solution is much simpler. The main confusation is that there is not just only one "source of truth" - you hold a state for each row and also all the do_ro_no's.
I suggest to keep track only for each row and calculate the arrayToPost whenever you need.
Like this:
angular.module('app', []).controller('ctrl', ($scope, $element) => {
$scope.truck_no = [];
$scope.RosList = [{
do_ro_no: "217PALV000201898",
slno: 1,
},
{
do_ro_no: "317PALV000201898",
slno: 2,
}
];
$scope.getTruckNo = () => {
return $scope.truck_no.filter((t, index) => {
return $scope.RosList[index].checked;
});
}
$scope.getArrayToPost = () => {
return $scope.RosList
.filter(ros => ros.checked)
.map(ros => ros.do_ro_no);
}
$scope.arrayToPost = [];
$scope.toggleCheckAll = function() {
if ($scope.checkedAll) {
//angular.forEach($scope.RosList, function(user, truckno) {
// user.checked = true;
// $scope.modifyArrayToPost(user, truckno);
//});
$scope.RosList.forEach(ros => ros.checked = true);
} else {
//angular.forEach($scope.RosList, function(user, truckno) {
// user.checked = false;
// $scope.modifyArrayToPost(user, truckno);
//});
$scope.RosList.forEach(ros => ros.checked = false);
}
}
//$scope.modifyArrayToPost = function(user, truckno) {
// if (user.checked && truckno != null && $scope.arrayToPost.indexOf(user.do_ro_no) == -1) {
// $scope.arrayToPost.push(user.do_ro_no, truckno);
// } else if (!user.checked) {
// $scope.arrayToPost.splice($scope.arrayToPost.indexOf(user.do_ro_no, truckno), 2);
// }
//}
//$scope.$watch('RosList', function() {
// var allSet = true;
// var allClear = true;
// angular.forEach($scope.RosList, function(user, truckno) {
// if (user.checked) {
// allClear = false;
// } else {
// allSet = false;
// }
// });
//
// var checkAll = $element.find('#all');
// checkAll.prop('indeterminate', false);
// if (allSet) {
// $scope.checkedAll = true;
// } else if (allClear) {
// $scope.checkedAll = false;
// } else {
// $scope.checkedAll = false;
// checkAll.prop('indeterminate', true);
// }
//}, true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<table class='reportstd' align='center' width='80%'>
<tr class='trdesign'>
<td>
<input type="checkbox" name="checkAll" id="all" data-ng-model="checkedAll" data-ng-change="toggleCheckAll()" />
</td>
<td> Sl No</td>
<td> RO No.</td>
<td> Truck No.</td>
</tr>
<tr data-ng-repeat="user in RosList">
<td> <input type="checkbox" value="{{user.do_ro_no}}" data-ng-model="user.checked" data-ng-change="modifyArrayToPost(user,truck_no[$index])" /> </td>
<td>{{$index + 1}}</td>
<td>{{user.do_ro_no}}</td>
<td><input type='text' data-ng-model="truck_no[$index]" id="truck_no_{{$index}}" name="truck_no_{{$index}}" value=""></td>
</tr>
</table>
<table>
<tr>
<td colspan='2'><input type="submit" id="btn_submit" name='sea' value='Search' data-ng-submit="postROs(arrayToPost)" /></td>
</tr>
</table>
<pre>
{{getTruckNo() | json}}
</pre>
</div>
The array is the result of getTruckNo() as you can see in the snippet.

How to Send multiple values from Asp.Net WebApi to Angularjs Controller?

WebApi Controller.. How to send this value to Angularjs controller (bill = q.TotalBill;)? I have send this (return Ok(gridlist);) into JSON form into angularjs controller
public static double bill; // this is static variable on top of a class
[System.Web.Http.Route("api/Products/gridpro/{id}")]
public IHttpActionResult GetGrid(int id)
{
var q = db.products.Find(id);
if (q != null)
{
var check = gridlist.Where(x => x.Id == id).FirstOrDefault();
if (check != null)
{
check.ProductQty += 1;
check.TotalAmount = check.ProductQty * check.ProductRate;
}
else
{
q.ProductQty = 1;
q.TotalAmount = q.ProductQty * q.ProductRate;
gridlist.Add(q);
}
q.TotalBill = gridlist.Sum(x => x.TotalAmount);
foreach (var item in gridlist)
{
item.TotalBill = q.TotalBill;
}
bill = q.TotalBill; //How to send this value to Angularjs controller
return Ok(gridlist);
}
else
{
return NotFound();
}
}
Anagularjs Code: I see all the data into the HTML using this ($scope.gridproducts) but I want to show (bill = q.TotalBill;) this single value into HTML code
$scope.OnProChange = function (Pro) {
var id = Pro.Id;
$http.get("/api/Products/gridpro/" + id).then(function (response) {
console.log(JSON.stringify(response.data))
$scope.gridproducts = response.data;
})
}
HTML code:How I can show total bill value I use {{gridproducts.TotalBill}} this but nothing works.
<tbody>
<tr ng-repeat="item in gridproducts">
<td>
<a class="delete"><i class="fa fa-times-circle-o"></i></a>
</td>
<td class="name">{{item.ProductName}}</td>
<td>{{item.ProductRate}}</td>
<td>
<input class="form-control qty" style="width:50px" onchange="UpdatePurchaseItem('36',this.value)" value="{{item.ProductQty}}">
</td>
<td>{{item.TotalAmount}}</td>
</tr>
<tr></tr>
<tfoot>
<tr>
<th colspan="2"></th>
<th colspan="2"><b>Total</b></th>
<th><b>{{gridproducts.TotalBill}}</b></th>
</tr>
<tr>
<th colspan="2"><b></b></th>
<th colspan="2"><b>Total Items</b></th>
<th><b>25</b></th>
</tr>
</tfoot>
</tbody>
if you want send multiple values to angularjs , you may create complex type for that.
for example,
in c# code
Public Class GridDataModel<T>
{
public T ItemList{get;set;}
public int TotalBill{get;set}
}
then when you return data to js
var gridData=new GridDataModel<products>()
{
ItemList=gridlist,
TotalBill=q.TotalBill
}
return Ok(gridData);
after doing this , you can create another propert for js scope
$http.get("/api/Products/gridpro/" + id).then(function (response) {
console.log(JSON.stringify(response.data))
$scope.gridproducts = response.data.ItemList;
$scope.totalBill = response.data.TotalBill;
})

Checkbox checked not updating on delete, its updating the second time

i have a code like this:
<body ng-app="UserManagement" ng-controller="UserManagementController">
<h3>to do</h3>
<form ng-submit="addtodo();">
<table>
<tr><td colspan="2"><input type="checkbox" ng-model="employees.todo" /></td></tr>
<tr><td colspan="2">{{remng()}} of {{actuallength}} remaining</td></tr>
<tr ng-repeat="emp in employees">
<td><input type="checkbox" ng-model="emp.todo" /></td>
<td>{{emp.name}}</td>
</tr>
<tr>
<td><input type="text" ng-model="addemp" /></td>
<td><input type="button" value="Add" ng-click="addemps()"/></td>
</tr>
<tr>
<td><input type="button" value="Delete" ng-click="deleteemps();"/></td>
</tr>
</table>
</form>
</body>
here i am making simple add, delete operation of a list of employees. In the delete operation, when i click delete without checking any checkbox, the items with existing checked checkboxes are deleted, but when i click any checkbox and press delete, the clicked checkbox is not deleted this time, but when i click delete second time, it deletes.
Js code:
var app = angular.module("UserManagement", []);
//Controller Part
app.controller("UserManagementController", function($scope, $http) {
$scope.employees = [
{name:'Abhinav',todo:true},
{name:'Amit', todo:false},
{name:'Raghav',todo:true},
{name:'Sumit', todo:false},
{name:'Ashwani',todo:true},
{name:'Mihir', todo:false},
]
$scope.totalsel = $scope.employees.length;
$scope.actuallength = $scope.totalsel;
alert($scope.actuallength);
//$scope.addtodo = function(){}
//alert("ddd");
$scope.deleteemps = function(){
//alert($scope.employees.name);
$scope.deleted_emps = [];
//alert("in foreach: "+$scope.employees[2].todo);
angular.forEach($scope.employees, function(todos, index) {
//alert(todos.todo);
//alert(todos.name);
if(todos.todo){
// alert(index)
var deletednames = todos.name;
// var deletedtodo = todos.todo;
//$scope.deleted_emps.push(deletednames)
// alert(deletednames);
$scope.deleted_emps.push({name:todos.name, todo:todos.todo});
//var abc=angular.toJson($scope.deleted_emps);
// alert(index);
//console.log(angular.toJson(todos.name));
console.log("hiii: "+$scope.deleted_emps.name);
var indx;
for (var i=0; i<$scope.deleted_emps.length; i++) {
console.log("iii: "+$scope.deleted_emps[i].name);
console.log("i: "+$scope.employees[index].name);
//console.log($scope.employees[index].name.indexOf($scope.deleted_emps[i].name));
indx = $scope.employees[index].name.indexOf($scope.deleted_emps[i].name);
// alert(indx);
if (indx > -1) {
// alert(indx);
//$scope.employees.splice()
$scope.employees.splice(index, 1);
}
}
/* var indx;
for (var i=0; i<array2.$scope.deleted_emp; i++) {
indx = array1.indexOf(array2[i]);
if (indx > -1) {
array1.splice(indx, 1);
}
}
*/
}
$scope.actuallength = $scope.totalsel;
})
}
});
I am using angular js 1.6.1 . Thanks in advance.
I've made a fiddle based on your codes.
Add and Delete Employees
Sample code of mine is like this.
$scope.deleteEmp = function(){
var slicedEmps = [];
angular.forEach($scope.employees, function(e){
if(!e.isChecked){
slicedEmps.push(e);
}
});
$scope.employees = slicedEmps;
};
What I suggested is making new array instead of using 'splice'.
I hope this fiddle can help you. :)

AngularJS: Summing nested objects from multiple objects

Based in the following table I need to get the total of all subtotals.
I have tried to use the same sumByKey filter but I does't work.
Plus, the sum of all subtotals must be based on the result of the filter, it means, If we have two results (two categories) the sum of subtotals must be based on those objects. Any idea?
html
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Category</th>
<th>Products with quantities</th>
<th>Subtotal of quantities</th>
</tr>
</thead>
<tbody align="center">
<tr data-ng-repeat="category in categories | filter:search">
<td>{{$index+1}}</td>
<td>{{category.name}}</td>
<td>{{category.products}}</td>
<td>{{category.products | sumByKey:'quantity'}}</td>
</tr>
</tbody>
<thead align="right">
<tr>
<td colspan="3"><strong>Total</strong></td>
<td></td>
</tr>
</thead>
</table>
angularjs
var app = angular.module("app", []);
app.controller("controllerApp", function($scope, $http){
$http.get("categories.json").success(function(data) {
$scope.categories = data;
});
});
app.filter('sumByKey', function () {
return function (data, key) {
if (typeof (data) === 'undefined' || typeof (key) === 'undefined') {
return 0;
}
var sum = 0;
for (var i = data.length - 1; i >= 0; i--) {
sum += parseInt(data[i][key]);
}
return sum;
}
});
May not be Angular solution. But you can also get total by pure JavaScript.
By keeping a total $scope varaible like this inside your controller
$scope.total = getTotal(data);
function getTotal(data){
var total = 0;
data.forEach(function(item){
item.products.forEach(function(product){
total += product.quantity;
})
});
return total;
}
Here is the updated Plunker.
It can be done with angular also.
Example : http://plnkr.co/edit/zhTtoOjW7J1oumktlvFP?p=preview
HTML:
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Category</th>
<th>Products with quantities</th>
<th>Subtotal of quantities</th>
</tr>
</thead>
<tbody align="center">
<tr data-ng-repeat="category in filterValues=(categories | filter:search)">
<td>{{$index+1}}</td>
<td>{{category.name}}</td>
<td>{{category.products}}</td>
<td>{{category.products | sumByKey:'quantity'}}</td>
</tr>
</tbody>
<thead align="right">
<tr>
<td colspan="3"><strong>Total</strong></td>
<td>{{filterValues | sumOfValue:'quantity'}}</td>
</tr>
</thead>
</table>
JS:
// Code goes here
var app = angular.module("app", []);
app.controller("controllerApp", function($scope, $http) {
$http.get("categories.json").success(function(data) {
$scope.categories = data;
});
});
app.filter('sumByKey', function() {
return function(data, key) {
if (typeof(data) === 'undefined' || typeof(key) === 'undefined') {
return 0;
}
var sum = 0;
for (var i = data.length - 1; i >= 0; i--) {
sum += parseInt(data[i][key]);
}
return sum;
}
});
app.filter('sumOfValue', function() {
return function(data, key) {
if (angular.isUndefined(data) || angular.isUndefined(key)) {
return 0;
}
var sum = 0;
for (var i = 0; i < data.length; i++) {
var value = data[i];
if (!angular.isUndefined(value)) {
for (var j = 0; j < value.products.length; j++) {
sum += parseInt(value.products[j][key]);
}
}
}
return sum;
}
});

Angular pagination reverse jumping

I have this table:
Here is a code and Fiddle:
HTML
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th class="id">Id <a ng-click="sort_by('id')"><i class="icon-sort"></i></a></th>
<th class="name">Name <a ng-click="sort_by('name')"><i class="icon-sort"></i></a></th>
<th class="description">Description <a ng-click="sort_by('description')"><i class="icon-sort"></i></a></th>
<th class="field3">Field 3 <a ng-click="sort_by('field3')"><i class="icon-sort"></i></a></th>
<th class="field4">Field 4 <a ng-click="sort_by('field4')"><i class="icon-sort"></i></a></th>
<th class="field5">Field 5 <a ng-click="sort_by('field5')"><i class="icon-sort"></i></a></th>
</tr>
</thead>
<tfoot>
<td colspan="6">
<div class="pagination pull-right">
<ul>
<li ng-class="{disabled: currentPage == 0}">
<a href ng-click="prevPage()">« Prev</a>
</li>
<li ng-repeat="n in range(pagedItems.length, currentPage, currentPage + gap) "
ng-class="{active: n == currentPage}"
ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: (currentPage) == pagedItems.length - 1}">
<a href ng-click="nextPage()">Next »</a>
</li>
</ul>
</div>
</td>
</tfoot>
<pre>pagedItems.length: {{pagedItems.length|json}}</pre>
<pre>currentPage: {{currentPage|json}}</pre>
<tbody>
<tr ng-repeat="item in pagedItems[currentPage] | orderBy:sortingOrder:reverse">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td>{{item.field3}}</td>
<td>{{item.field4}}</td>
<td>{{item.field5}}</td>
</tr>
</tbody>
</table>
JS
function ctrlRead($scope, $filter) {
// init
$scope.sortingOrder = 'name';
$scope.gap = 5;
$scope.cached = 0;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 5;
$scope.pagedItems = [];
$scope.currentPage = 0;
$scope.items = [
{"id":1,"name":"name 1","description":"description 1","field3":"field3 1","field4":"field4 1","field5 ":"field5 1"},
{"id":2,"name":"name 2","description":"description 1","field3":"field3 2","field4":"field4 2","field5 ":"field5 2"},
//....
];
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.items, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.range = function (size,start, end) {
if( $scope.cached == start){
start = start - 4;
console.log('start',start);
}
$scope.cached = start;
var ret = [];
console.log(size,start, end);
if(size < 2){return ret;}
if (size < end) {
end = size;
start = size-$scope.gap;
}
for (var i = start; i < end; i++) {
if(i<0) continue;
ret.push(i);
}
console.log(ret);
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function(newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
};
};
ctrlRead.$inject = ['$scope', '$filter'];
From the code you can see that we have 13 groups of 5 rows.
If I press in pagination on 5, the 5 button jumps to 1st place and last place is 9.
By this way I can "travel" quickly over all data.
My problem that I don't know how to make it wok to jump back a.e reverse.
For example if I stay on 13:
and I press on 9 I expect that 9 will jump to the end of pagination and 1st element in list will be 5.
How to achieve that?
Thank you,
In general you need to decouple the idea of your current page index and the indices of your page navigation links. There are lots of ways to do this though. I did this by adding a left and right gap to the range you are creating, which better control the indices of the quick nav buttons. So when you call setPage I just add a little check:
if (this.n <= $scope.currentPage) {
$scope.left_gap = $scope.gap-1;
$scope.right_gap = 1;
} else {
$scope.left_gap = 0;
$scope.right_gap = $scope.gap;
}
This way, when you click to the left of your current page, it will do the correct gaps so that the clicked index will be on the right, but the right clicking behavior still works. You just have to use:
<li ng-repeat="n in range(pagedItems.length, currentPage - left_gap, currentPage + right_gap) ">
This is not without it's bugs though, and you will still need to fix making sure you always keep 5 around, but I'll leave that to you. Here is the fiddle to play with.
Hope this helped!

Resources