【问题标题】:angular: checkbox group's validation is out of sync with the model角度:复选框组的验证与模型不同步
【发布时间】:2014-08-22 02:21:44
【问题描述】:

这组复选框需要至少选中一个才能启用提交按钮。
取消选中所有复选框会禁用该按钮。
所有复选框都使用相同的范围属性 (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

【问题讨论】:

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


    【解决方案1】:

    您应该只使用 ng-click 而不是手动将事件绑定到 DOM 元素上。此外,在控制器中访问 DOM 也不是一个好习惯。如果你让它来处理事件,你就不会遇到这些问题,你也可以安全地删除手动 $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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-03
      • 2016-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多