计算AngularJS ng-repeat中重复元素的总和

下面的脚本使用ng-repeat显示商店购物车。 对于数组中的每个元素,它显示项目名称,数量和小计( product.price * product.quantity )。

计算重复元素总价格的最简单方法是什么?

 <table> <tr> <th>Product</th> <th>Quantity</th> <th>Price</th> </tr> <tr ng-repeat="product in cart.products"> <td>{{product.name}}</td> <td>{{product.quantity}}</td> <td>{{product.price * product.quantity}} €</td> </tr> <tr> <td></td> <td>Total :</td> <td></td> <!-- Here is the total value of my cart --> </tr> </table> 

在模板中

 <td>Total: {{ getTotal() }}</td> 

在控制器中

 $scope.getTotal = function(){ var total = 0; for(var i = 0; i < $scope.cart.products.length; i++){ var product = $scope.cart.products[i]; total += (product.price * product.quantity); } return total; } 

这也是filter和正常列表。 首先为列表中所有值的总和创build一个新的filter,并给出总数量总和的解决scheme。 详细代码检查它的提琴手链接

 angular.module("sampleApp", []) .filter('sumOfValue', function () { return function (data, key) { if (angular.isUndefined(data) || angular.isUndefined(key)) return 0; var sum = 0; angular.forEach(data,function(value){ sum = sum + parseInt(value[key], 10); }); return sum; } }).filter('totalSumPriceQty', function () { return function (data, key1, key2) { if (angular.isUndefined(data) || angular.isUndefined(key1) || angular.isUndefined(key2)) return 0; var sum = 0; angular.forEach(data,function(value){ sum = sum + (parseInt(value[key1], 10) * parseInt(value[key2], 10)); }); return sum; } }).controller("sampleController", function ($scope) { $scope.items = [ {"id": 1,"details": "test11","quantity": 2,"price": 100}, {"id": 2,"details": "test12","quantity": 5,"price": 120}, {"id": 3,"details": "test3","quantity": 6,"price": 170}, {"id": 4,"details": "test4","quantity": 8,"price": 70} ]; }); 
 .col-lg-2, .col-lg-4, .col-lg-8, .col-lg-12 { float: left; } .col-lg-12 { width: 100%; } .col-lg-8 { width: 66.66666667%; } .col-lg-4 { width: 33.33333333%; } .col-lg-2 { width: 16.66666667%; } .text-right { float: right; } 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="sampleApp"> <div ng-controller="sampleController"> <div class="col-lg-12"> <label>Search</label> <input type="text" class="form-control" ng-model="searchFilter" /> </div> <div class="col-lg-12"> <div class="col-lg-2"> <h4>Id</h4> </div> <div class="col-lg-4"> <h4>Details</h4> </div> <div class="col-lg-2 text-right"> <h4>Quantity</h4> </div> <div class="col-lg-2 text-right"> <h4>Price</h4> </div> <div class="col-lg-2 text-right"> <h4>Total</h4> </div> <div ng-repeat="item in resultValue=(items | filter:{'details':searchFilter})"> <div class="col-lg-2">{{item.id}}</div> <div class="col-lg-4">{{item.details}}</div> <div class="col-lg-2 text-right">{{item.quantity}}</div> <div class="col-lg-2 text-right">{{item.price}}</div> <div class="col-lg-2 text-right">{{item.quantity * item.price}}</div> </div> <div colspan='3' class="col-lg-8 text-right"> <h4>{{resultValue | sumOfValue:'quantity'}}</h4> </div> <div class="col-lg-2 text-right"> <h4>{{resultValue | sumOfValue:'price'}}</h4> </div> <div class="col-lg-2 text-right"> <h4>{{resultValue | totalSumPriceQty:'quantity':'price'}}</h4> </div> </div> </div> </div> 

意识到这个答案很久以前,但想提出不同的方法没有提出… … –

使用ng-init来计算你的总数。 这样,您不必在HTML中迭代并在控制器中迭代。 在这种情况下,我认为这是一个更清洁/更简单的解决scheme。 (如果计数逻辑比较复杂,我肯定会build议把逻辑移到控制器或服务上。)

  <tr> <th>Product</th> <th>Quantity</th> <th>Price</th> </tr> <tr ng-repeat="product in cart.products"> <td>{{product.name}}</td> <td>{{product.quantity}}</td> <td ng-init="itemTotal = product.price * product.quantity; controller.Total = controller.Total + itemTotal">{{itemTotal}} €</td> </tr> <tr> <td></td> <td>Total :</td> <td>{{ controller.Total }}</td> // Here is the total value of my cart </tr> 

当然,在你的控制器中,只需定义/初始化你的Total字段:

 // random controller snippet function yourController($scope..., blah) { var vm = this; vm.Total = 0; } 

你可以计算内部ng-repeat总数如下:

 <tbody ng-init="total = 0"> <tr ng-repeat="product in products"> <td>{{ product.name }}</td> <td>{{ product.quantity }}</td> <td ng-init="$parent.total = $parent.total + (product.price * product.quantity)">${{ product.price * product.quantity }}</td> </tr> <tr> <td>Total</td> <td></td> <td>${{ total }}</td> </tr> </tbody> 

检查结果: http : //plnkr.co/edit/Gb8XiCf2RWiozFI3xWzp?p=preview

这是我的解决scheme

甜美简单的自定义filter:

(但只涉及到简单的价值总和,而不是sum产品,我已经做了sumProductfilter,并将其作为编辑附加到这个职位)。

 angular.module('myApp', []) .filter('total', function () { return function (input, property) { var i = input instanceof Array ? input.length : 0; // if property is not defined, returns length of array // if array has zero length or if it is not an array, return zero if (typeof property === 'undefined' || i === 0) { return i; // test if property is number so it can be counted } else if (isNaN(input[0][property])) { throw 'filter total can count only numeric values'; // finaly, do the counting and return total } else { var total = 0; while (i--) total += input[i][property]; return total; } }; }) 

JS小提琴

编辑:sumProduct

这是sumProductfilter,它接受任何数量的参数。 作为一个参数,它接受来自input数据的属性名称,并且可以处理嵌套属性(由dot: property.nested标记的嵌套);

  • 传递零参数返回input数据的长度。
  • 仅传递一个参数就返回该属性值的简单总和。
  • 传递更多的参数返回传递的属性(标量和属性)的值的乘积之和。

这里是JS小提琴和代码

 angular.module('myApp', []) .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 = data[key[j]]; return data; } } }) 

JS小提琴

解决这个问题的另一种方法,从瓦茨拉夫的答案延伸解决这个特定的计算 – 即在每一行计算。

  .filter('total', function () { return function (input, property) { var i = input instanceof Array ? input.length : 0; if (typeof property === 'undefined' || i === 0) { return i; } else if (typeof property === 'function') { var total = 0; while (i--) total += property(input[i]); return total; } else if (isNaN(input[0][property])) { throw 'filter total can count only numeric values'; } else { var total = 0; while (i--) total += input[i][property]; return total; } }; }) 

为了做到这一点,只需要将一个计算函数添加到您的范围,例如

 $scope.calcItemTotal = function(v) { return v.price*v.quantity; }; 

您可以在HTML代码中使用{{ datas|total:calcItemTotal|currency }} 。 这具有不被每个摘要调用的优点,因为它使用filter,并且可以用于简单或复杂的总计。

的jsfiddle

这是一个简单的方法来做到这一点与ng-repeat和ng-init来聚合所有的值,并扩展与item.total属性的模型。

 <table> <tr ng-repeat="item in items" ng-init="setTotals(item)"> <td>{{item.name}}</td> <td>{{item.quantity}}</td> <td>{{item.unitCost | number:2}}</td> <td>{{item.total | number:2}}</td> </tr> <tr class="bg-warning"> <td>Totals</td> <td>{{invoiceCount}}</td> <td></td> <td>{{invoiceTotal | number:2}}</td> </tr> </table> 

ngInit指令调用每个项目的集合函数。 控制器中的setTotals函数计算每个项目总数。 它还使用invoiceCount和invoiceTotal范围variables来汇总(汇总)所有项目的数量和总额。

 $scope.setTotals = function(item){ if (item){ item.total = item.quantity * item.unitCost; $scope.invoiceCount += item.quantity; $scope.invoiceTotal += item.total; } } 

有关更多信息和演示请看这个链接:

http://www.ozkary.com/2015/06/angularjs-calculate-totals-using.html

简单的scheme

这是一个简单的解决scheme。 没有额外的循环所需。

HTML部分

  <table ng-init="ResetTotalAmt()"> <tr> <th>Product</th> <th>Quantity</th> <th>Price</th> </tr> <tr ng-repeat="product in cart.products"> <td ng-init="CalculateSum(product)">{{product.name}}</td> <td>{{product.quantity}}</td> <td>{{product.price * product.quantity}} €</td> </tr> <tr> <td></td> <td>Total :</td> <td>{{cart.TotalAmt}}</td> // Here is the total value of my cart </tr> </table> 

脚本部分

  $scope.cart.TotalAmt = 0; $scope.CalculateSum= function (product) { $scope.cart.TotalAmt += (product.price * product.quantity); } //It is enough to Write code $scope.cart.TotalAmt =0; in the function where the cart.products get allocated value. $scope.ResetTotalAmt = function (product) { $scope.cart.TotalAmt =0; } 

我喜欢优雅的解决scheme

在模板中

 <td>Total: {{ totalSum }}</td> 

在控制器中

 $scope.totalSum = Object.keys(cart.products).map(function(k){ return +cart.products[k].price; }).reduce(function(a,b){ return a + b },0); 

如果您使用ES2015(又名ES6)

 $scope.totalSum = Object.keys(cart.products).map(function(k){ return +cart.products[k].price; }).reduce((a,b) => a + b); 

我对RajaShilpa的回答进行了扩展。 你可以使用如下语法:

 {{object | sumOfTwoValues:'quantity':'products.productWeight'}} 

这样就可以访问一个对象的子对象。 以下是filter的代码:

 .filter('sumOfTwoValues', function () { return function (data, key1, key2) { if (typeof (data) === 'undefined' || typeof (key1) === 'undefined' || typeof (key2) === 'undefined') { return 0; } var keyObjects1 = key1.split('.'); var keyObjects2 = key2.split('.'); var sum = 0; for (i = 0; i < data.length; i++) { var value1 = data[i]; var value2 = data[i]; for (j = 0; j < keyObjects1.length; j++) { value1 = value1[keyObjects1[j]]; } for (k = 0; k < keyObjects2.length; k++) { value2 = value2[keyObjects2[k]]; } sum = sum + (value1 * value2); } return sum; } }); 

以瓦茨拉夫的答案,使其更像angular:

 angular.module('myApp').filter('total', ['$parse', function ($parse) { return function (input, property) { var i = input instanceof Array ? input.length : 0, p = $parse(property); if (typeof property === 'undefined' || i === 0) { return i; } else if (isNaN(p(input[0]))) { throw 'filter total can count only numeric values'; } else { var total = 0; while (i--) total += p(input[i]); return total; } }; }]); 

这给你甚至访问嵌套和数组数据的好处:

 {{data | total:'values[0].value'}} 

在html中

 <b class="text-primary">Total Amount: ${{ data.allTicketsTotalPrice() }}</b> 

在JavaScript中

  app.controller('myController', function ($http) { var vm = this; vm.allTicketsTotalPrice = function () { var totalPrice = 0; angular.forEach(vm.ticketTotalPrice, function (value, key) { totalPrice += parseFloat(value); }); return totalPrice.toFixed(2); }; }); 

Huy Nguyen的回答几乎就在那里。 要使其工作,请添加:

 ng-repeat="_ in [ products ]" 

…到ng-init的行。 该列表总是有一个单一的项目,所以angular度会重复该块只有一次。

Zybnek的演示使用过滤可以通过添加:

 ng-repeat="_ in [ [ products, search ] ]" 

请参阅http://plnkr.co/edit/dLSntiy8EyahZ0upDpgy?p=preview

在阅读完所有答案之后 – 如何总结分组信息,我决定跳过这一切,只是加载一个SQL JavaScript库。 我使用的是alasql,是的,它加载时间需要几秒的时间,但节省了无数的时间在编码和debugging,现在分组和sum()我只是使用,

 $scope.bySchool = alasql('SELECT School, SUM(Cost) AS Cost from ? GROUP BY School',[restResults]); 

我知道这听起来像是对angular / js的咆哮,但是SQL在30多年前就已经解决了,我们不应该在浏览器中重新创build它。