【问题标题】:Why does ng-click on checkbox update the value of array after function is called?为什么调用函数后 ng-click on checkbox 会更新数组的值?
【发布时间】:2015-10-19 19:59:43
【问题描述】:

我有一个包含有分数的人的数组。我显示带有分数的人员列表和一个复选框。当用户选中复选框时,我会将所有选中的分数加起来。: http://jsfiddle.net/edwardtanguay/hwutbgv3/16

但是,总数落后了一个检查,因为当 Angular 执行 ng-click 中包含的函数时,它似乎没有更新 ng-model 的值。

如何让 Angular 先更新值,然后执行函数?

<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()
}

【问题讨论】:

  • 我认为你可以使用 ng-change 而不是 ng-click。

标签: angularjs checkbox


【解决方案1】:

发生这种情况是因为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
};

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

我选择最后一个是因为我觉得它更干净。

【讨论】:

  • 虽然这行得通,但它仍然是一种反模式
【解决方案2】:

不要自己更新视图数据,为此使用数据绑定。只需将您的 updateTotals-function 重命名为 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 并让 Angular 为您完成工作。

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

【讨论】:

    猜你喜欢
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多