angular:复选框组验证与模型不同步

时间:2014-08-22 02:21:45

标签: javascript angularjs angularjs-scope angularjs-validation angular-digest

复选框组要求至少检查一个以启用提交按钮 取消选中所有复选框将禁用该按钮 所有复选框都使用相同的范围属性(showRequired),以根据需要标记它们。

发生的情况是,第一次点击不会启用按钮。选择和取消选择其他复选框会使整个事情失控;无论复选框处于什么状态,任何给定的点击都可以启用或不启用该按钮。

令人不安地拍摄它,我看到的是 ng-valid 类并不总是适用于所有复选框。有时它在一个复选框上,有时它在所有这些复选框上,或者某些组合。使用 $ timeout 修复了所有内容,但我不知道为什么,使用定时器会产生错误的代码异味。必须有更好的方法。

我可以手动调用验证函数,使视图与模型内联:

 angular.element(document.querySelectorAll('.cb')).scope().checkBoxes()

...让我想到我正在迈向$ digest循环。



以下仅在使用$ timeout:

时有效
angular.module('app', []).
    controller('testCtrl', function ($scope, $timeout) {
        $scope.guests = [
                            {name:'stephen', lname:'wille'},
                            {name:'mary', lname:'torccaso'}
                        ];
        $scope.form = {};
        $scope.form.cb = {one:false, two:false, three:false, four:false}
        $scope.showRequired = true;

        $scope.checkBoxes = function ()
        {
            console.log('checkbox');
            $scope.showRequired = !($scope.form.cb.one || $scope.form.cb.two ||
                                    $scope.form.cb.three || $scope.form.cb.four);
            $scope.$apply();

        };
        $scope.login = function () {
            console.log('login');
        };

        angular.element(document.querySelectorAll('.cb'))
                .on('click', function () {
                    console.log('click');
                    $scope.checkBoxes();

                /* 
                 * using the $timeout solves the problem, but why?
                 *  
                    $timeout(function () {
                        $scope.checkBoxes();
                    }, 0, false);
                */
                });
    });

$ timeout触发另一个$ digest,但$ scoope也是如此。$ apply()。
什么给出了什么?

Plunker example

1 个答案:

答案 0 :(得分:2)

您应该只使用ng-click而不是手动绑定DOM元素上的事件。此外,在控制器中访问DOM也不是一个好习惯。如果你把它放到angular来处理你不会遇到这些问题的事件,你也可以安全地删除手动的$ digest调用($ scope。$ apply())。还可以使用ng-change事件而不是ng-click来正确获取模型值,因为复选框的模型值会在更改事件中获得更新。

所以基本上你的脚本只是: -

$scope.handleChange = function(){
    $scope.checkBoxes();
};

和html: -

    <input class="cb" type="checkbox" value="1" ng-model="form.cb.one"
            ng-required="showRequired" ng-change="handleClick()">one</input>
    <input class="cb" type="checkbox" value="2" ng-model="form.cb.two"
           ng-required="showRequired" ng-change="handleClick()">two</input>
    <input class="cb" type="checkbox" value="3" ng-model="form.cb.three"
           ng-required="showRequired" ng-change="handleClick()">three</input>
    <input class="cb" type="checkbox" value="4" ng-model="form.cb.four"
           ng-required="showRequired" ng-change="handleClick()">four</input>

<强> Demo

使用ng-repeat实际上可以更好地改善这一点。

如果您重新排列数组中的复选框: -

$scope.form.cb = [{text:'one', value:false}, {text:'two', value:false}, {text:'three', value:false}, {text:'four', value:false}];

你可以只取消一个: -

<label ng-repeat="chk in form.cb">
 <input class="cb" type="checkbox" value="{{$index}}" 
      ng-model="chk.value" ng-required="showRequired" 
      ng-change="handleChange()"/> {{chk.text}}</label>

脚本将只是: -

$scope.handleChange = function(){
  $scope.showRequired = $scope.form.cb.every(function(itm) {
     return !itm.value;
  });
};

现在这很灵活,它完全是模型驱动的,足够灵活,无需修改你的html或逻辑就可以添加更多复选框。

<强> Demo2

<强> Array.prototype.every shim support for older browsers