为什么ng-click on checkbox会在调用函数后更新数组的值?

时间:2015-10-19 10:34:41

标签: angularjs checkbox

我有一个有分数的人的阵列。我会显示带有分数和复选框的人员列表。当用户选中复选框时,我会检查所有已检查的分数: http://jsfiddle.net/edwardtanguay/hwutbgv3/16

然而,由于看起来当Angular执行ng-click中包含的函数时,总计是一个检查,因此它没有更新ng-model的值。

如何让Angular更新值FIRST,然后执行该功能?

<div ng-controller="MyCtrl">
    <ul>
        <li ng-repeat="person in persons | orderBy:'score'"><input type="checkbox" ng-model="person.isChecked" ng-click="updateTotals()"/> {{person.name}} = {{person.score}} ({{person.isChecked}}) 

        </li>
    </ul>
    <div>{{message}}</div>
    <div>total score of checked persons: {{total}}</div>
</div> 
var myApp = angular.module('myApp',[]);

function MyCtrl($scope, $window) {

    $scope.debug = '';
    $scope.total = 0;

    $scope.persons = [
        {score: 1, name: 'Jim', isChecked: true},
        {score: 2, name: 'Joe', isChecked: false},
        {score: 3, name: 'Angie', isChecked: true}
    ];

    $scope.updateTotals = function() {
        $scope.total = 0;
        for(var x=0; x < $scope.persons.length; x++) {
            var person = $scope.persons[x];
            if(person['isChecked']) {
                $scope.total += person['score'];   
            }
        }
    }

    $scope.updateTotals()
}

2 个答案:

答案 0 :(得分:2)

这是因为ng-clickng-model更改之前触发,因此您需要使用ng-change而不是ng-click

<li ng-repeat="person in persons | orderBy:'score'">
    <input type="checkbox" ng-model="person.isChecked" ng-change="updateTotals(person)"/>
    .....
</li>

这是一个DEMO

此外,你可以摆脱控制器updateTotals()并在视图中管理它,如

在控制器中定义总数

// using a object because we need this inside `ng-repeat` which create a child scope, otherview we need to call it as $parent.total in the view.
$scope.all = {
    total: 0
};

in html

<ul>
    <li ng-repeat="person in persons | orderBy:'score'" ng-init="person.isChecked ? (all.total = all.total+person.score) : return">
        <input type="checkbox" ng-model="person.isChecked" ng-change="person.isChecked ? (all.total = all.total+person.score) : (all.total = all.total-person.score)"/>
        {{person.name}} = {{person.score}} ({{person.isChecked}})
    </li>
</ul>

使用ng-init计算初始阶段的总数

...ng-init="person.isChecked ? (all.total = all.total+person.score) : return"...

更改复选框值时添加或减少分数

<input type="checkbox" ng-model="person.isChecked" ng-change="person.isChecked ? (all.total = all.total+person.score) : (all.total = all.total-person.score)"/>

这是DEMO

如果您认为html有点混乱,请移动条件并将总数更新为controller

在初始阶段和复选框更改阶段调用updateTotal并传递参数(person&amp; true/false以指示初始阶段)

<li ng-repeat="person in persons | orderBy:'score'" ng-init="updateTotal(person, true)">
    <input type="checkbox" ng-model="person.isChecked" ng-change="updateTotal(person, false)"/>
    {{person.name}} = {{person.score}} ({{person.isChecked}})
</li> 
控制器中的

$scope.updateTotal = function(person, isInitPhase) {
    if (isInitPhase) {
        if (person.isChecked) {
            $scope.total += person.score;
        }
    } else {
        if (person.isChecked) {
          $scope.total += person.score;
        } else {
            $scope.total -= person.score;
        }
    }
}

这是DEMO

我选择最后一个,因为我觉得它更清洁。

答案 1 :(得分:0)

不要自己更新视图数据,请使用数据绑定。只需将updateTotals - 函数重命名为getTotal,然后将其返回计算总数:

$scope.getTotal = function() {
    var total = 0;

    for(var x=0; x < $scope.persons.length; x++) {
        var person = $scope.persons[x];
        if(person['isChecked']) {
            total += person['score'];   
        }
    }

    return total;
}

并将模板更改为显示getTotal()

<div>total score of checked persons: {{getTotal()}}</div>

现在,您可以删除复选框上的ng-click,让角色为您完成工作。

另外,我建议您查看controllerAs-syntax并开始使用it has a number of different advantages, including readability and removing $scope from your code