Nested ng repeat failure in angular js - angularjs

Try to do a nest ng-repeat, parent ng-repeat works but not for its child
1.Created object and insert data when app init
2.display data by calling ng-repeat
angular.module('lipapp', []).controller('lipapp_Module_Control', function ($scope, $http, $window) {
$scope.CompaignBasket = [];
$scope.CompaignBasketTotal = 0;
$scope.CompaignBasketCauseTotal = [];
//Sample Data Section, Real data plz go to $scope.UpdateCompaign function
$scope.InitialCompaignBasket = function () {
$scope.CompaignBasket = [];
var causeAmount = [];
var causeitem = 0;
var donorDetail = {};
donorDetail.Date = '2/14/13';
donorDetail.Donor = 'George Smith';
donorDetail.City = 'Los Angelos';
donorDetail.State = 'CA';
donorDetail.Total = 400;
causeAmount = []; //forloop Dynamic Insert!
causeAmount.push(10);
causeAmount.push(0);
causeAmount.push(500);
causeAmount.push(0);
causeAmount.push(1000);
causeAmount.push(0);
//causeitem = 0;causeAmount.push(causeitem); or I should use this format?
donorDetail.DonorCauseAmount = causeAmount;
$scope.CompaignBasketTotal += donorDetail.Total;
$scope.CompaignBasket.push(donorDetail);
console.log( $scope.CompaignBasket);
...
}
All the result display correctly but the item.donorCauseAmount has throw errors
<tr ng-repeat="item in CompaignBasket">
<td>{{item.Date}}</td>
<td>{{item.Donor}}</td>
<td>{{item.City}}</td>
<td>{{item.State}}</td>
<td ng-repeat="cause_item in item.DonorCauseAmount">{{cause_item}} </td>
<td>${{item.Total|number :0}}</td>
</tr>
Also for when I try to calculate the total for different CauseItem in the same col in script there is also a repeater error
for(var i=0; i< $scope.CompaignBasket.length; i++)
{
if (i == 0)
{
$scope.CauseTotalAmount = $scope.CompaignBasket[i].DonorCauseAmount;
console.log($scope.CauseTotalAmount);
}
else {
for (var j = 0; j < $scope.CauseTotalAmount.length; j++) {
// $scope.CauseTotalAmount[j] += $scope.CompaignBasket[i].DonorCauseAmount[j];
console.log('total '+ $scope.CompaignBasket[i].DonorCauseAmount[j]); //Error show up by this!!!
}
}
console.log($scope.CauseTotalAmount);
}
How can I solve it?

You need to use a track by index when you have duplicate values within the array.
<td ng-repeat="cause_item in item.DonorCauseAmount track by $index">{{cause_item}} </td>

Related

Get filtered value from view to controller

I use ng-repeat to show my array of objects. One of the attributes is video duration, and I used filter to directly show sum of all meta_durations. here is filter
app.filter('sumProduct', function() {
return function (input) {
var i = input instanceof Array ? input.length : 0;
var a = arguments.length;
if (a === 1 || i === 0)
return i;
var keys = [];
while (a-- > 1) {
var key = arguments[a].split('.');
var property = getNestedPropertyByKey(input[0], key);
if (isNaN(property))
throw 'filter sumProduct can count only numeric values';
keys.push(key);
}
var total = 0;
while (i--) {
var product = 1;
for (var k = 0; k < keys.length; k++)
product *= getNestedPropertyByKey(input[i], keys[k]);
total += product;
}
return total;
function getNestedPropertyByKey(data, key) {
for (var j = 0; j < key.length; j++)
// data = dataDuration[key[j]];
data = data.meta_duration;;
return data;
}
}
})
and in view
<table>
<thead>
<tr>
<th>Media name</th>
<th>Media type</th>
<th>Media duration in sec</th>
<th>Media thumbnail</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="media in myMediaItems">
<td>{{media.name}}</td>
<td>{{media.type}}</td>
<td>>{{media.meta_duration}}</td>
<td><img src="{{media.thumbnail}}" alt="" /></td>
</tr>
</tbody>
<tr>
<td></td>
<td></td>
<td>Total duration {{ myMediaItems|sumProduct:'duration' }}</td> //here is where i use custom filter
<td></td>
</tr>
</table>
How to get total duration value in the controller?
Dynamically i add (push) media to list from another list with all media.
$scope.addToMediaList = function(item) {
var seconds = parseInt(item.meta_duration);
$scope.view_duration = Math.floor(moment.duration(seconds,'seconds').asHours()) + ':' + moment.duration(seconds,'seconds').minutes() + ':' + moment.duration(seconds,'seconds').seconds();($scope.view_duration_seconds, "HH:mm:ss");
$scope.myMediaItems.push(item);
$scope.sumDuration = $filter("sumProduct")(myMediaItems.meta_duration); //i try like this, set on $scope.sumDuration but in conole i get only number 0
$scope.myMediaItemsId.push(item.id);
$scope.input = "";
};
Thanks
I simplified your filter.
try this
app.filter('sumProduct', function() {
return function (input) {
var i = input instanceof Array ? input.length : 0;
var a = arguments.length;
if (i === 0)
return i;
var total = 0;
for(var x of input){
var duration = parseFloat(x.meta_duration);
if(isNaN(duration)){
throw 'filter sumProduct can count only numeric values';
}
total += duration;
}
return total;
}
});
You can use something like this
<div ng-init="sumDuration = myMediaItems|sumProduct:'duration'"> </div>
I solved this by forwarding the returned value from the custom filter to controller.
var filtered = $filter('sumProduct')($scope.myMediaItems);
console.log(filtered)
Filtered value is sum. thnx # Amaya San

Table binding with Angular

I'm trying to make a table footer auto-update but the ng-repeat and even the regular double-braces does not appear to auto-bind when the $scope value is updated.
https://jsfiddle.net/r0pk793e/3/
Specifically, I'm setting the value $scope.hello and incrementing it when the table updates (when the user changes a value in the table cells). Though I can see the value changes, it does not get re-bound to the HTML.
I believe this table should be updated by the following function, but it is not...
<table class="tg">
<tr>
<td class="tg-yw4l" ng-repeat="item in items">{{item}}</td>
</tr>
</table>
The $scope.hello does change, as illustrated by the console.log($scope.hello);
var doUpdate = function () {
var items = [];
for (var c = 0; c < headings.length; c++) {
if (typeof (hot.getDataAtCell(0, c)) == "number") {
var levelTotal = 0;
var i = 0;
do {
levelTotal += hot.getDataAtCell(i, c);
i++;
} while (hot.getDataAtCell(i, c) != null);
items.push(levelTotal);
}
else
{
items.push(' ');
}
}
$scope.items = items;
$scope.hello = $scope.hello + 1;
console.log($scope.hello);
}
When I tested your fiddle everything got updated
anyway if this still not working call $scope.$apply(); after updating your values and you will see the magic happening.

how to calculate the sum of amount for same names in ng-repeat using angularjs

here is app.js
AllServices.teamAllDataFunction1(User)
.then(function(response) {
$scope.User.data=response.data['DeatilTeam'];
console.log($scope.User.data);
var sum = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
sum += parseInt($scope.User.data[i].dp_inst_pending) || 0;
}
});
here m getting all data in which so many records having same name but differnt pending amount, so i want to show only single name and the summation of there penging amount, so that i can show it in single row. I'm not getting how to achieve it.. please help me..
here is html,
<table ng-table>
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in User.data" ng-if="data.dp_inst_pending && data.dp_inst_pending == 0">
<td>{{data.AdvisorName}}</td>
<td>{{data.dp_inst_pending}}</td>
</tr>
</table>
in this way i 'm getting data
code has few generic issues, let's resolve that first.
First of all, assuming your data.dp_inst_pending is Integer, you have used it directly in ng-if. In that case, if someone actually has zero pending amount it won't be displayed.
Secondly, you want to calculate sum of pending amount for those accounts which have same name. for that you will have to run a double for loop. One to check names and other to add pending amount if name is same. I have created one sample for the same, which i think satisfies your requirements. Please go through it and optimize as required.
var myApp = angular.module("myApp", []);
myApp.controller("MyController", ['$scope',
function($scope) {
$scope.User = {};
$scope.User.data = [{
"advisor_name": "Test1",
"dp_inst_pending": 300
}, {
"advisor_name": "Test2",
"dp_inst_pending": 0
}, {
"advisor_name": "Test1",
"dp_inst_pending": 500
}, {
"advisor_name": "Test2",
"dp_inst_pending": 600
}, {
"advisor_name": "Test1",
"dp_inst_pending": 15
}, {
"advisor_name": "Test2",
"dp_inst_pending": 150
}, {
"advisor_name": "Test3",
"dp_inst_pending": 30
}];
$scope.User.summedData = [];
var sums = [];
var advisorNames = [];
for (i = 0; i < $scope.User.data.length; i++) {
var key = $scope.User.data[i].advisor_name;
if (advisorNames.indexOf(key) >= 0) {} else {
var sumOfKey = 0;
for (j = 0; j < $scope.User.data.length; j++) {
if ($scope.User.data[j].advisor_name == key) {
sumOfKey += $scope.User.data[j].dp_inst_pending;
}
}
sums.push(sumOfKey);
advisorNames.push(key);
}
}
$scope.Test = {};
$scope.Test.data = [];
for (k = 0; k < sums.length; k++) {
$scope.Test.data[k] = {
"advisor_name": advisorNames[k],
"dp_inst_pending": sums[k]
}
}
console.log(sums);
console.log(advisorNames);
console.log($scope.Test.data);
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController">
<table ng-table>
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in Test.data">
<td>{{data.advisor_name}}</td>
<td>{{data.dp_inst_pending}}</td>
</tr>
</table>
</div>
</div>
I am not optimizing it, as it should be done by you.

The ng-repeat array is updating table data for the first time i'm selecting value, but its not updating the table data only once

I'm trying to update the table view depending on select option. The table view is updating only once, when i select the option second time the view is not updating, I'm not getting what's the problem. please help me solve this..
here is app.js
$scope.User = {};
$scope.arr = [];
$scope.loaddata = function(User) {
$scope.User.site = layouts;
AllServices.teamAllDataFunction1(User)
.then(function(response) {
$scope.User.data=response.data;
});
};
$scope.getdatalayoutwise = function(User) {
var total = 0;
var total1 = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
if($scope.User.data[i].Layout == $scope.User.selectedSite) {
total += parseInt($scope.User.data[i].dp_inst_pending);
$scope.arr.push($scope.User.data[i]);
}
}
for (var j = 0; j < ($scope.User.data1).length; j++) {
if($scope.User.data1[j].Layout == $scope.User.selectedSite) {
total1 += parseInt($scope.User.data1[j].DP_Inst_Pending);
}
}
$scope.User.teamTotal = total;
$scope.User.personalTotal = total1;
$scope.data = [$scope.User.teamTotal, $scope.User.personalTotal];
$scope.totamnt = parseInt($scope.User.personalTotal) + parseInt($scope.User.teamTotal);
$scope.User.totalamount = $filter('translate')('totalpending') + ": " + $filter('currency')($scope.totamnt, "");
$scope.User.data = $scope.arr;
};
here is html
<select name="site" ng-model="User.selectedSite" ng-change="getdatalayoutwise(User)">
<option value="">--{{'selectsite_message' | translate}}--</option>
<option ng-repeat= "option in User.site" value="{{option.Layout}}">{{option.Layout}}</option>
</select>
<table ng-table>
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in User.data | filter : {Layout: User.selectedSite}: true" ng-if="data.dp_inst_pending">
<td class="ui-helper-center"><a ng-click="advisorDetails($index, data, User)">{{data.AdvisorName}}</a></td>
<td>{{data.dp_inst_pending | currency:"₹":0}}</td>
</tr>
</table>
you need to use $scope.$apply() :
$scope.getdatalayoutwise = function(User) {
$scope.$apply(function () {
var total = 0;
var total1 = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
if($scope.User.data[i].Layout == $scope.User.selectedSite) {
total += parseInt($scope.User.data[i].dp_inst_pending);
$scope.arr.push($scope.User.data[i]);
}
}
...
});
}
https://www.grafikart.fr/formations/angularjs/apply-watch-digest
Change your function to this
$scope.loaddata = function(User) {
$scope.User.data = [];
$scope.User.site = layouts;
AllServices.teamAllDataFunction1(User)
.then(function(response) {
$scope.User.data=response.data;
});
and add a ng-if
<table ng-table ng-if="User.data.length">
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in User.data | filter : {Layout: User.selectedSite}: true" ng-if="data.dp_inst_pending">
<td class="ui-helper-center"><a ng-click="advisorDetails($index, data, User)">{{data.AdvisorName}}</a></td>
<td>{{data.dp_inst_pending | currency:"₹":0}}</td>
</tr>
</table>
Add this as the first line in getdatalayoutwise () function:
$scope.arr = [];
got it working by just doing following
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.getdatalayoutwise = function(User) {
var total = 0;
var total1 = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
if($scope.User.data[i].Layout == $scope.User.selectedSite) {
total += parseInt($scope.User.data[i].dp_inst_pending);
$scope.arr.push($scope.User.data[i]);
}
}
...
$scope.safeApply (function () {
$scope.User.data = $scope.arr;
});
};

Angularjs summary row filter

I am trying to build a custom filter which would add a summary (avg) row to the array.
I'd like to use it like this:
<tr ng-repeat="item in items | summaryRow : ['col1', 'col1'] | orderBy : 'name'"
Here's what my filter looks like:
summaryRow.$inject = ['$parse', 'sumFilter'];
function summaryRow($parse, sumFilter) {
return function(array, fields, nameLabel) {
var row = { id: 0 }, l = array.length, setter;
row[nameLabel || 'name'] = 'Summary';
for (var i = 0, j = fields.length; i < j; i++) {
setter = $parse(fields[i]).assign;
setter(row, sumFilter(array, fields[i]) / l);
}
return array.concat(row);
}
}
The thing is I want this extra row to be sortable and aware of changes within items. The problem is I'm running into the "10 $digest() iterations reached. Aborting!" issue. Any help would be appreciated, thanks!
Try using $filter in your controller. Here is a great post written by Todd Motto:
https://toddmotto.com/use-controller-filters-to-prevent-digest-performance-issues/
Found the solution, here's what I came up with:
summaryRow.$inject = ['$parse', 'sumFilter'];
function summaryRow($parse, sumFilter) {
var row = {};
return function(array, fields, nameLabel) {
clearObject(row);
var l = array.length, setter;
row.id = 0;
row[nameLabel || 'name'] = 'Summary';
for (var i = 0, j = fields.length; i < j; i++) {
setter = $parse(fields[i]).assign;
setter(row, sumFilter(array, fields[i]) / l);
}
return array.concat(row);
}
}
And here's the clearObject implementation:
function clearObject(obj) {
for (var k in obj)
delete obj[k];
}

Resources