我有一个表单的输入字段和验证设置通过添加所需的属性等。但对于某些字段,我需要做一些额外的验证。我如何“输入”到FormController控制的验证?

自定义验证可以是类似于“如果这3个字段被填写,那么这个字段是必需的,需要以特定的方式格式化”。

FormController中有一个方法。$setValidity,但这看起来不像一个公共API,所以我宁愿不使用它。创建一个自定义指令并使用NgModelController看起来是另一种选择,但基本上需要我为每个自定义验证规则创建一个指令,这是我不想要的。

实际上,从控制器标记字段为无效(同时也保持FormController同步)可能是我在最简单的场景中需要完成的工作,但我不知道如何做到这一点。


当前回答

我扩展了@Ben Lesh的答案,指定验证是否区分大小写(默认)

使用:

<input type="text" name="fruitName" ng-model="data.fruitName" blacklist="Coconuts,Bananas,Pears" caseSensitive="true" required/>

代码:

angular.module('crm.directives', []).
directive('blacklist', [
    function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            scope: {
                'blacklist': '=',
            },
            link: function ($scope, $elem, $attrs, modelCtrl) {

                var check = function (value) {
                    if (!$attrs.casesensitive) {
                        value = (value && value.toUpperCase) ? value.toUpperCase() : value;

                        $scope.blacklist = _.map($scope.blacklist, function (item) {
                            return (item.toUpperCase) ? item.toUpperCase() : item
                        })
                    }

                    return !_.isArray($scope.blacklist) || $scope.blacklist.indexOf(value) === -1;
                }

                //For DOM -> model validation
                modelCtrl.$parsers.unshift(function (value) {
                    var valid = check(value);
                    modelCtrl.$setValidity('blacklist', valid);

                    return value;
                });
                //For model -> DOM validation
                modelCtrl.$formatters.unshift(function (value) {
                    modelCtrl.$setValidity('blacklist', check(value));
                    return value;
                });
            }
        };
    }
]);

其他回答

Angular-UI的项目包含一个ui-validate指令,它可能会帮助你做到这一点。它让你指定一个函数来调用来进行验证。

看看演示页面:http://angular-ui.github.com/,向下搜索Validate标题。

从演示页面:

<input ng-model="email" ui-validate='{blacklist : notBlackListed}'>
<span ng-show='form.email.$error.blacklist'>This e-mail is black-listed!</span>

然后在你的控制器中:

function ValidateCtrl($scope) {
  $scope.blackList = ['bad@domain.example','verybad@domain.example'];
  $scope.notBlackListed = function(value) {
    return $scope.blackList.indexOf(value) === -1;
  };
}

更新:

改进和简化了之前指令的版本(一个而不是两个),功能相同:

.directive('myTestExpression', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            var expr = attrs.myTestExpression;
            var watches = attrs.myTestExpressionWatch;

            ctrl.$validators.mytestexpression = function (modelValue, viewValue) {
                return expr == undefined || (angular.isString(expr) && expr.length < 1) || $parse(expr)(scope, { $model: modelValue, $view: viewValue }) === true;
            };

            if (angular.isString(watches)) {
                angular.forEach(watches.split(",").filter(function (n) { return !!n; }), function (n) {
                    scope.$watch(n, function () {
                        ctrl.$validate();
                    });
                });
            }
        }
    };
}])

使用示例:

<input ng-model="price1" 
       my-test-expression="$model > 0" 
       my-test-expression-watch="price2,someOtherWatchedPrice" />
<input ng-model="price2" 
       my-test-expression="$model > 10" 
       my-test-expression-watch="price1" 
       required />

结果:相互依赖的测试表达式,其中验证器在更改其他指令模型和当前模型时执行。

测试表达式有局部$model变量,您应该使用它与其他变量进行比较。

以前:

我已经尝试通过添加额外的指令来改进@Plantface代码。如果我们的表达式需要在多个ngModel变量中进行更改时执行,这个额外的指令非常有用。

.directive('ensureExpression', ['$parse', function($parse) {
    return {
        restrict: 'A',
        require: 'ngModel',
        controller: function () { },
        scope: true,
        link: function (scope, element, attrs, ngModelCtrl) {
            scope.validate = function () {
                var booleanResult = $parse(attrs.ensureExpression)(scope);
                ngModelCtrl.$setValidity('expression', booleanResult);
            };

            scope.$watch(attrs.ngModel, function(value) {
                scope.validate();
            });
        }
    };
}])

.directive('ensureWatch', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        require: 'ensureExpression',
        link: function (scope, element, attrs, ctrl) {
            angular.forEach(attrs.ensureWatch.split(",").filter(function (n) { return !!n; }), function (n) {
                scope.$watch(n, function () {
                    scope.validate();
                });
            });
        }
    };
}])

示例:如何使用它来交叉验证字段:

<input name="price1"
       ng-model="price1" 
       ensure-expression="price1 > price2" 
       ensure-watch="price2" />
<input name="price2" 
       ng-model="price2" 
       ensure-expression="price2 > price3" 
       ensure-watch="price3" />
<input name="price3" 
       ng-model="price3" 
       ensure-expression="price3 > price1 && price3 > price2" 
       ensure-watch="price1,price2" />

当ng-model或任何一个ensure-watch变量发生变化时,执行Ensure-expression来验证模型。

编辑:下面添加了关于ngMessages (>= 1.3.X)的信息。

标准表单验证消息(1.0.;X及以上)

因为这是你谷歌“Angular Form Validation”得到的最多的结果之一,现在,我想为那些从那里来的人添加另一个答案。

FormController中有一个方法。$setValidity,但这看起来不像一个公共API,所以我宁愿不使用它。

这是“公开的”,不用担心。使用它。这就是它的作用。如果不打算使用它,Angular开发人员会在闭包中对它进行私有化。

要进行自定义验证,如果你不想像其他答案建议的那样使用Angular-UI,你可以简单地滚动你自己的验证指令。

app.directive('blacklist', function (){ 
   return {
      require: 'ngModel',
      link: function(scope, elem, attr, ngModel) {
          var blacklist = attr.blacklist.split(',');

          //For DOM -> model validation
          ngModel.$parsers.unshift(function(value) {
             var valid = blacklist.indexOf(value) === -1;
             ngModel.$setValidity('blacklist', valid);
             return valid ? value : undefined;
          });

          //For model -> DOM validation
          ngModel.$formatters.unshift(function(value) {
             ngModel.$setValidity('blacklist', blacklist.indexOf(value) === -1);
             return value;
          });
      }
   };
});

下面是一些用法的例子:

<form name="myForm" ng-submit="doSomething()">
   <input type="text" name="fruitName" ng-model="data.fruitName" blacklist="coconuts,bananas,pears" required/>
   <span ng-show="myForm.fruitName.$error.blacklist">
      The phrase "{{data.fruitName}}" is blacklisted</span>
   <span ng-show="myForm.fruitName.$error.required">required</span>
   <button type="submit" ng-disabled="myForm.$invalid">Submit</button>
</form>

注:在1.2。X,最好用ng-if代替上面的ng-show

这里是一个强制性的活塞链接

此外,我还写了一些关于这个主题的博客文章,内容更详细一些:

Angular表单验证

自定义验证指令

编辑:在1.3.X中使用ngMessages

现在你可以使用ngMessages模块来代替ngShow来显示错误消息。它实际上可以与任何东西一起工作,它不一定是一个错误消息,但这里是基本的:

包含<script src="angular-messages.js"></script> .js 在模块声明中引用ngMessages: Var app = angular。模块(“myApp”,[' ngMessages ']); 添加适当的标记: <表单名称= " personForm " > <input type="email" name="email" ng-model="person. "电子邮件“要求/ > < div ng-messages = " personForm.email。美元错误”> 需要< div ng-message = "需要" > < / div > <div ng-message="email">无效邮件</div> < / div > > < /形式

在上面的标记中,ng-message="personForm.email。$error"基本上指定ng-message子指令的上下文。然后ng-message="required"和ng-message="email"指定要监视的上下文属性。最重要的是,它们还指定了办理入住的顺序。它在列表中发现的第一个“真实”的信息获胜,它将显示该信息,而不显示其他信息。

ngMessages示例的plunker

在AngularJS中,定义自定义验证的最佳位置是Cutsom指令。 AngularJS提供了一个ngMessages模块。

ngMessages是一个用来显示和隐藏消息的指令 基于所监听的键/值对象的状态。的 指令本身补充了ngModel的错误消息报告 $error对象(存储验证错误的键/值状态)。

对于自定义表单验证,应该使用带有自定义指令的ngMessages模块。这里我有一个简单的验证,它将检查数字长度是否小于6在屏幕上显示错误

 <form name="myform" novalidate>
                <table>
                    <tr>
                        <td><input name='test' type='text' required  ng-model='test' custom-validation></td>
                        <td ng-messages="myform.test.$error"><span ng-message="invalidshrt">Too Short</span></td>
                    </tr>
                </table>
            </form>

下面是如何创建自定义验证指令

angular.module('myApp',['ngMessages']);
        angular.module('myApp',['ngMessages']).directive('customValidation',function(){
            return{
            restrict:'A',
            require: 'ngModel',
            link:function (scope, element, attr, ctrl) {// 4th argument contain model information 

            function validationError(value) // you can use any function and parameter name 
                {
                 if (value.length > 6) // if model length is greater then 6 it is valide state
                 {
                 ctrl.$setValidity('invalidshrt',true);
                 }
                 else
                 {
                 ctrl.$setValidity('invalidshrt',false) //if less then 6 is invalide
                 }

                 return value; //return to display  error 
                }
                ctrl.$parsers.push(validationError); //parsers change how view values will be saved in the model
            }
            };
        });

$setValidity是一个内置函数,用于设置模型状态为有效/无效

调用服务器的自定义验证

使用ngModelController $asyncValidators API来处理异步验证,比如向后端发送$http请求。添加到对象中的函数必须返回一个promise,该promise在有效时必须被解析,在无效时必须被拒绝。正在进行的异步验证通过key存储在ngModelController.$pending中。更多信息请参见AngularJS开发者指南-表单(自定义验证)。

ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
  var value = modelValue || viewValue;

  // Lookup user by username
  return $http.get('/api/users/' + value).
     then(function resolved() {
       //username exists, this means validation fails
       return $q.reject('exists');
     }, function rejected() {
       //username does not exist, therefore this validation passes
       return true;
     });
};

有关更多信息,请参见

ngModelController $asyncValidators API AngularJS开发者指南-表单(自定义验证)。


使用$validators API

接受的答案使用$parsers和$formatters管道添加一个自定义同步验证器。AngularJS 1.3+添加了一个$validators API,这样就不需要在$parsers和$formatters管道中添加验证器了:

app.directive('blacklist', function (){ 
   return {
      require: 'ngModel',
      link: function(scope, elem, attr, ngModel) {           
          ngModel.$validators.blacklist = function(modelValue, viewValue) {
              var blacklist = attr.blacklist.split(',');
              var value = modelValue || viewValue;
              var valid = blacklist.indexOf(value) === -1;
              return valid;
          });    
      }
   };
});

更多信息请参见AngularJS ngModelController API Reference - $validators。