在所选复选框上使用AngularJs计算摘要

时间:2014-05-25 11:53:14

标签: javascript angularjs

我正在学习AngularJs并且我已经使用ng-repeat创建了一个动态列表,但现在我找不到下一步的解决方案......

我有以下代码:

HTML:

<div ng-app="app">
    <div class="list" ng-controller="ListController">

        <div class="row" ng-repeat="prod in prodList">
            <div class="prod-name cell">
                <input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" value="{{ prod.id }}" data-cb="" /><label for="prod-{{ prod.id }}">{{ prod.name }}</label>
            </div>
            <div class="prod-size cell">
                <label for="prodColor-@{{ prod.id }}">
                    <select id="prodColor-{{ prod.id }}" data-ng-model="orders.prods.color[prod.id]" data-ng-options="color.id as color.name for color in prod.colors">
                        <option value="">Select one</option>
                    </select>
                </label>
            </div>
            <div class="prod-price cell">
                {{ prod.price }}
            </div>

        </div>

        <div class="sum">
            {{ sum }}
        </div>

    </div>
</div>

JS:

var app = angular.module("app", [], function () {
});

app.controller('ListController', function ($scope) {
    init();

    function init () {
        $scope.prodList = [{"id":"1","name":"window","colors":[{"id":"9","name":"white"},{"id":"11","name":"black"}],"price":"100"},{"id":"2","name":"door","colors":[{"id":"22","name":"blue"},{"id":"23","name":"red"}],"price":"356"},{"id":"3","name":"table","colors":[{"id":"37","name":"white"},{"id":"51","name":"black"}],"price":"505"}];
        $scope.orders = {};
        $scope.orders.prods = {};
        $scope.orders.prods.prod = {};
        $scope.orders.prods.color = {};
        $scope.sum = 0;
    }
});

工作演示:

http://jsfiddle.net/HDrzR/

问题

如何在$scope.sum中计算所选产品价格的摘要?

编辑:

因此,如果从列表中选择“窗口”和“表格”,则总和应包含606.但如果取消选择“表格”,则总和应为100。

提前谢谢!

5 个答案:

答案 0 :(得分:2)

您可以$watch超过$scope.orders.prod并重新计算总和或(如果效果不是主要问题且对象列表不是很大)您可以使用sum()在视图中起作用并引用它:

Total: {{sum()}}

$scope.sum = function () {
    return $scope.prodList.filter(function (prod) {
        return $scope.orders.prods.prod[prod.id];
    }).reduce(function (subtotal, selectedProd) {
        return subtotal + parseInt(selectedProd.price);
    }, 0);
};

/* If the above looks complicated, it is the equivalent of: */
$scope.sum = function () {
    var sum = 0;
    for (var i = 0; i < $scope.prodList.length, i++) {
        var prod = $scope.prodList[i];
        if ($scope.orders.prods.prod[prod.id]) {
            sum += parseInt(prod.price);
        }
    }
    return sum;
}

如果你决定走下观察路径,这就是代码的样子:

Total: {{watchedSum}}

$scope.sum = ...;   // same as above
$scope.$watchCollection('orders.prods.prod', function (newValue, oldValue) {
    if (newValue !== undefined) {
        $scope.watchedSum = $scope.sum();
    }
});

<子> 的更新:
“偷”Quad的$watchCollection因为这比$watch(..., true)更“便宜” 只要$scope.order.prods.prod仅包含边缘值(即没有对象),$watchCollection就足以检测到更改。


另请参阅此 short demo ,说明这两种方法。

答案 1 :(得分:1)

这是一个更新的小提琴。 http://jsfiddle.net/HRQ9u/

我所做的是在订单上添加$scope.$watch

         $scope.$watch('orders', function (newValue, oldValue) {
            var findProdById = function (products, id) {
                for (var i = 0; i < products.length; i++) {
                    if (parseInt(products[i].id, 10) === parseInt(id, 10)) {
                        return products[i];
                    }
                }
                return null;
            };
            var orders = newValue;

            var usedProducts = newValue.prods.prod;
            var sum = 0;
            for ( var prop in usedProducts ){
               var prodList = $scope.prodList;
               var id = prop;
               if ( usedProducts[id] ){
                   var product = findProdById(prodList, id);
                   if ( product !== null ){
                       sum += parseInt(product.price, 10);
                   }
               }
            }
            $scope.sum = sum;
        }, true);

编辑:

话虽如此,你可以大大简化你的模型。我的意思是很多。

另外,我只使用常规js而不是lodash或下划线。

答案 2 :(得分:1)

更新了您的小提琴FIDDLE

你可以$ scope。$ watchCollection你的范围来计算新的总和。我将你的prodList价格改为数字而不是字符串,并使用underscore.js更容易在你的对象/数组中循环。

 $scope.$watchCollection("orders.prods.prod",function(){
    var sum = 0;
    for(var i = 0;i<$scope.prodList.length;i++){
        if($scope.orders.prods.prod[$scope.prodList[i].id]){
            sum += $scope.prodList[i].price;
        }
    }
    $scope.sum = sum; 
});

watchCollection docs are here

编辑:使用常规js回答更改

答案 3 :(得分:1)

使用复选框注册 ng-click 并传递 $ event &amp; prod.id 引用了一个自定义函数,该函数将在复选框点击事件中调用。

 <input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" value="{{ prod.price }}" ng-click="calcSum($event, prod.id)" data-cb="" />

控制器中将自定义功能定义为:

$scope.calcSum = function($event, id) {
         var checkbox = $event.target;

        if (checkbox.checked  ) {
            $scope.sum += parseInt(checkbox.value);   
         } else {
            $scope.sum -= parseInt(checkbox.value);    
         }  
}

更改复选框属性以存储 {{prod.price}} 而不是{{prod.id}},这更有意义。

答案 4 :(得分:1)

从我的POV中,使用来自ngChange本身的 input[checkbox] 更合适。像:

ng-change="addMe(prod.price);"

我们需要一种方法来区分已检查和未检查,并且为了减少您的应用程序,我们将通过这种方式使用对象的存在:

ng-change="addMe(orders.prods.prod[prod.id],prod.price);"
ng-true-value="{{ prod.id }}" 
ng-false-value=""

完整的 HTML 将如下所示:

<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" ng-change="addMe(orders.prods.prod[prod.id],prod.price);" ng-true-value="{{ prod.id }}" ng-false-value="" />

通过控制器,您只需在必要时添加或减少:

$scope.addMe=function(checked,val){
  val = 1*val
  if (!checked){ $scope.sum = $scope.sum-val;}
  else { $scope.sum =  $scope.sum +val; }
}

以下是Online Demo