使用指令进行AngularJS表单初始化验证

10

我有一个名为valid-number的验证指令,用于使用$setValidity设置表单的有效性 - 对于我在应用指令作为属性的输入框中键入的任何文本值,这都可以正常工作。

HTML代码如下:

<form name="numberForm">
<input name="amount" type="text" ng-model="amount" required  valid-number /></form>
以下是指示:
angular.module('test',[]).directive('validNumber',function(){
            return{
                require: "ngModel",
                link: function(scope, elm, attrs, ctrl){

                    var regex=/\d/;
                    ctrl.$parsers.unshift(function(viewValue){
                        var floatValue = parseFloat(viewValue);

                        if(regex.test(viewValue)){
                            ctrl.$setValidity('validNumber',true);
                        }
                        else{
                            ctrl.$setValidity('validNumber',false);
                        }
                        return viewValue;
                    });
                }
            };
        });

但是,我也希望在页面第一次加载时,如果输入框初始化的值无效,例如如果我设置$scope.amount = 'not a number',那么验证也会被触发并将 CSS 设置为无效类。我期望输入框已经应用了该指令,但却没有成功。为了将“not a number”标记为无效,我必须更改输入框内容,这样才能触发该指令。

如何确保指令适用于任何用<input>初始化的内容?

完整的代码示例在此处:http://jsfiddle.net/JW43C/5/

3个回答

16

$parsers 数组包含一组函数,这些函数会被应用于模型从视图中接收到的值(即用户输入的内容),$formatters 数组包含一组函数,这些函数会在将模型的值显示在视图中之前被应用于该值。

在您的指令中,您正确地使用了 $parsers 数组,但是如果要验证初始值,您还需要添加 $formatters 数组:

angular.module('test',[]).directive('validNumber',function(){
  return{
    require: "ngModel",
    link: function(scope, elm, attrs, ctrl){
      var regex = /^\d$/;
      var validator = function(value){
        ctrl.$setValidity('validNumber', regex.test(value));
        return value;
      };

      ctrl.$parsers.unshift(validator);
      ctrl.$formatters.unshift(validator);
    }
  };
});

演示示例


1
非常棒的文章,它强调了一些重要细节,如$parsers和$formatters,在文档中很难找到。 - Tobias
刚开始涉及复杂的跨字段验证,这篇文章救了我一天——或者说把一天变成了几分钟呢! - bchesley
你救了我的一天。谢谢! - fmquaglia

1

在链接阶段,您可以简单地调用验证函数,就像在此 fiddle 中一样:

link: function(scope, elm, attrs, ctrl) {                       
    var regex=/\d/;
    var verificationFunction = function(viewValue) {
        var floatValue = parseFloat(viewValue);

        if(regex.test(viewValue)) {
            ctrl.$setValidity('validNumber',true);
            return viewValue;
        }
        else {
            ctrl.$setValidity('validNumber',false);
            return undefined;
        }
    };

    ctrl.$parsers.unshift(verificationFunction);
    verificationFunction();
}

0
在 (>=) angular 1.3.1 版本发布后,您可以使用一种稍微正确的方式来实现该行为,遵循 Angular 验证指令的样式(例如 requiredmaxlength)。
在这种情况下,您必须将您的验证器附加为 $validators 数组的属性,并且不再需要 $parsers$formatters

var app = angular.module('test', []);

app
  .directive('validNumber', function() {
    return {
      require: "ngModel",
      link: function(scope, elm, attrs, ctrl) {
        var regex = /^\d+$/;

        ctrl.$validators['validNumber'] = function(modelValue, viewValue) {
          return regex.test(viewValue);
        };
      }
    };
  });

app.controller('NumberCtrl', NumberCtrl);

function NumberCtrl($scope) {
  $scope.amount = '5z';
};
input.ng-invalid {
  background-color: #FA787E;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>

<div ng-app="test">
  <div ng-controller="NumberCtrl">

    <div ng-form name="numberForm">
      <input name="amount"
             type="text"
             ng-model="amount"
             required 
             valid-number />
      
      <span ng-show="numberForm.amount.$error.validNumber">
        Doesn't look like an integer
      </span>
    </div>        
  </div>
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接