带范围的Angular指令。$ watch强制验证其他字段

时间:2014-01-29 10:43:00

标签: javascript angularjs validation angularjs-directive

我写了一个match-model Angular指令,当用户在我的应用程序中注册时,我用它来进行密码/密码重复处理。密码重复字段具有此特定属性,可根据原始密码字段验证此字段。

我的指令有scope.$watch用于优化目的,因为每次我验证我的重复密码范围属性时我都不必读取相关的范围属性值,但我只是使用缓存的值,当相关的范围属性值发生更改时,该值会发生变化(原始密码)。

这是我的指示:

.directive("matchModel", ["$timeout", function ($timeout) {
    return {
        require: "ngModel",
        link: function (scope, element, attributes, ngModelController) {

            var valueCache = null;

            // watch "match-model" model property value
            scope.$watch(attributes["matchModel"], function (newValue, oldValue) {
                valueCache = newValue;
                /*
                scope.$apply(); // error $digest in progress
                $timeout(function () { scope.$digest(); }); // no error, not working
                $timeout(function () { scope.$apply(); }); // no error, not working
                */
            });

            // add model validation parser
            ngModelController.$parsers.unshift(function (value) {
                ngModelController.$setValidity("match", value === valueCache);
                return value === valueCache ? value : undefined;
            });
        }
    };
}]);

我的表单由两个字段组成(与此问题相关):

<input type="password" name="password" id="password" placeholder="password"
       class="validate" autocomplete="off"
       required
       ng-minlength="6"
       ng-model="data.password" />
<input type="password" name="passwordRepeat" id="passwordRepeat" placeholder="repeat password"
       class="validate" autocomplete="off"
       required
       ng-model="data.passwordRepeat"
       match-model="data.password" />

要求

  1. 当用户输入第一个密码时,当输入足够的字符时,字段变为有效 - 在上述情况下为6个字符
  2. 当用户输入第二个密码时,字段应在数据与第一个密码匹配时生效
  3. 如果用户返回第一个字段并更改原始密码,则第二个字段应无效
  4. 目前如何运作

    1和2按预期工作,但3没有。这就是我想添加scope.$digest以将范围模型更改传播到其他字段的原因。并且scope.$watch是正确的时刻,因为它在特定范围模型属性更改时执行。

    scope.$digest(或scope.$apply)似乎不验证模型。验证似乎没有与它一起执行。

    问题

    那么我应该如何做scope.$validate甚至更好element.$validate之类的事情,这样它才能验证我的特定字段而不是整个模型(导致UI中的表单无效)。

2 个答案:

答案 0 :(得分:3)

我会通过明确验证$watch

中的$ viewValue来实现

PLUNKER

app.directive("matchModel", [
  function () {
    return {
      require: "ngModel",
      link: function (scope, element, attributes, ngModelController) {

        var valueCache = null;

        scope.$watch(attributes["matchModel"], function (newValue, oldValue) {
          valueCache = newValue;
          validate(ngModelController.$viewValue);
        });

        var validate = function (value) {
          ngModelController.$setValidity("match", value === valueCache);
          return value === valueCache ? value : undefined;
        };

        ngModelController.$parsers.unshift(validate);
      }
    };
}]);

答案 1 :(得分:1)

我会这样做,只有一个地方检查它们是否相等:

app.directive("matchModel", function () {
    return {
        require: "ngModel",
        link: function (scope, element, attributes, ngModelController) {

            scope.$watch(function(){
               return scope.$eval(attributes["matchModel"]) == ngModelController.$viewValue; //only 1 place to check if they are equal
            }, function (newValue) {
                ngModelController.$setValidity("match", newValue);
            });

        }
    };
});

DEMO