首页 文章

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

提问于
浏览
105

下面的脚本显示了使用 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>

18 回答

  • 0

    采取Vaclav的答案并使其更像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'}}
    
  • 3

    在模板中

    <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;
    }
    
  • 0

    这也适用于过滤器和普通列表 . 首先要为列表中的所有值的总和创建一个新过滤器,并给出总量的总和的解决方案 . 在详细代码中检查它fiddler link .

    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}
            ];
        });
    

    检查这个Fiddle Link

  • 0

    很久以前意识到这个回答了,但想发布不提出的不同方法......

    使用 ng-init 计算总数 . 这样,您不必迭代HTML并在控制器中迭代 . 在这种情况下,我认为这是一个更简洁/更简单的解决方案 . (如果计数逻辑更复杂,我肯定会建议将逻辑移动到控制器或服务中 . )

    <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;
    }
    
  • 55

    您可以在 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

    如果自动更新结果:http://plnkr.co/edit/QSxYbgjDjkuSH2s5JBPf?p=preview(谢谢 - VicJordan)

  • 3

    这是我的解决方案

    甜美简单的自定义过滤器:

    (但只与简单的值之和,而不是和产品相关,我已经编制了 sumProduct 过滤器并将其作为编辑添加到此帖子中) .

    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

    这是 sumProduct 过滤器,它接受任意数量的参数 . 作为参数,它接受来自输入数据的属性的名称,并且它可以处理嵌套属性(嵌套标记为点: property.nested );

    • 传递零参数返回输入数据的长度 .

    • 仅传递一个参数会返回该属性的简单值 .

    • 传递更多参数会返回传递属性值的值乘积(属性的标量总和) .

    这里是JS Fiddle和代码

    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小提琴

  • 0

    Simple Solution

    这是一个简单的解决方案 . 无需额外的循环 .

    HTML part

    <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>
    

    Script Part

    $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;
     }
    
  • 40

    另一种解决方法,从Vaclav的answer扩展到解决这个特定的计算 - 即每行的计算 .

    .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 }} . 这样做的好处是不会为每个摘要调用,因为它使用过滤器,可用于简单或复杂的总计 .

    JSFiddle

  • 9

    这是使用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指令为每个项调用set total函数 . 控制器中的setTotals函数计算每个项目总数 . 它还使用invoiceCount和invoiceTotal范围变量来聚合(总和)所有项目的数量和总计 .

    $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

  • 1

    我喜欢优雅的解决方案

    In Template

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

    In Controller

    $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(k => +cart.products[k].price)
      .reduce((a, b) => a + b);
    
  • 142

    您可以尝试使用角度js的服务,它已经为我工作..下面的代码片段

    控制器代码:

    $scope.total = 0;
    var aCart = new CartService();
    
    $scope.addItemToCart = function (product) {
        aCart.addCartTotal(product.Price);
    };
    
    $scope.showCart = function () {    
        $scope.total = aCart.getCartTotal();
    };
    

    服务代码:

    app.service("CartService", function () {
    
        Total = [];
        Total.length = 0;
    
        return function () {
    
            this.addCartTotal = function (inTotal) {
                Total.push( inTotal);
            }
    
            this.getCartTotal = function () {
                var sum = 0;
                for (var i = 0; i < Total.length; i++) {
                    sum += parseInt(Total[i], 10); 
                }
                return sum;
            }
        };
    });
    
  • 4

    您可以使用自定义角度过滤器,该过滤器将数据集对象数组和每个对象中的键相加 . 然后过滤器可以返回总和:

    .filter('sumColumn', function(){
            return function(dataSet, columnToSum){
                let sum = 0;
    
                for(let i = 0; i < dataSet.length; i++){
                    sum += parseFloat(dataSet[i][columnToSum]) || 0;
                }
    
                return sum;
            };
        })
    

    然后在您的表中汇总您可以使用的列:

    <th>{{ dataSet | sumColumn: 'keyInObjectToSum' }}</th>
    
  • 1

    这是我解决这个问题的方法:

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

    脚本

    $scope.calculateVAT = function () {
        return $scope.cart.products.reduce((accumulator, currentValue) => accumulator + (currentValue.price * currentValue.quantity), 0);
    };
    

    reduce将针对products array中的每个产品执行 . 累加器是总累计量,currentValue是数组的当前元素,最后的0是初始值

  • 0

    我对RajaShilpa的答案进行了一些扩展 . 您可以使用以下语法:

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

    这样您就可以访问对象的子对象 . 以下是过滤器的代码:

    .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;
        }
    });
    
  • 16

    在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);
                };
            });
    
  • -2

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

    ng-repeat="_ in [ products ]"
    

    ...到ng-init的行 . 列表总是有一个项目,因此Angular将重复该块一次 .

    使用过滤的Zybnek演示可以通过添加以下内容来实现:

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

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

  • 1
    **Angular 6: Grand Total**       
     **<h2 align="center">Usage Details Of {{profile$.firstName}}</h2>
            <table align ="center">
              <tr>
                <th>Call Usage</th>
                <th>Data Usage</th>
                <th>SMS Usage</th>
                <th>Total Bill</th>
              </tr>
              <tr>
              <tr *ngFor="let user of bills$">
                <td>{{ user.callUsage}}</td>
                <td>{{ user.dataUsage }}</td>
                <td>{{ user.smsUsage }}</td>
           <td>{{user.callUsage *2 + user.dataUsage *1 + user.smsUsage *1}}</td>
              </tr>
    
    
              <tr>
                <th> </th>
                <th>Grand Total</th>
                <th></th>
                <td>{{total( bills$)}}</td>
              </tr>
            </table>**
    
    
        **Controller:**
            total(bills) {
                var total = 0;
                bills.forEach(element => {
    total = total + (element.callUsage * 2 + element.dataUsage * 1 + element.smsUsage * 1);
                });
                return total;
            }
    
  • 2

    在阅读了这里的所有答案 - 如何汇总分组信息之后,我决定跳过它并加载一个SQL javascript库 . 我正在使用alasql,是的,它在加载时间上需要几秒钟,但在编码和调试中节省了无数时间,现在要分组和sum()我只是使用,

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

    我知道这听起来像是对angular / js有点咆哮,但是30年前SQL解决了这个问题,我们不应该在浏览器中重新发明它 .

相关问题