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

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

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

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


当前回答

这里有一个很酷的方法来在一个表单中进行自定义通配符表达式验证(来自:AngularJS和过滤器的高级表单验证):

<form novalidate="">  
   <input type="text" id="name" name="name" ng-model="newPerson.name"
      ensure-expression="(persons | filter:{name: newPerson.name}:true).length !== 1">
   <!-- or in your case:-->
   <input type="text" id="fruitName" name="fruitName" ng-model="data.fruitName"
      ensure-expression="(blacklist | filter:{fruitName: data.fruitName}:true).length !== 1">
</form>
app.directive('ensureExpression', ['$http', '$parse', function($http, $parse) {
    return {
        require: 'ngModel',
        link: function(scope, ele, attrs, ngModelController) {
            scope.$watch(attrs.ngModel, function(value) {
                var booleanResult = $parse(attrs.ensureExpression)(scope);
                ngModelController.$setValidity('expression', booleanResult);
            });
        }
    };
}]);

jsFiddle演示(支持表达式命名和多个表达式)

它类似于ui-validate,但你不需要特定于作用域的验证函数(这是通用的),当然你也不需要ui。Utils这样。

其他回答

我扩展了@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;
                });
            }
        };
    }
]);

你可以在你的验证场景中使用ng-required(“如果这3个字段都填写了,那么这个字段是必须的”:

<div ng-app>
    <input type="text" ng-model="field1" placeholder="Field1">
    <input type="text" ng-model="field2" placeholder="Field2">
    <input type="text" ng-model="field3" placeholder="Field3">
    <input type="text" ng-model="dependentField" placeholder="Custom validation"
        ng-required="field1 && field2 && field3">
</div>

调用服务器的自定义验证

使用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。

这里有一个很酷的方法来在一个表单中进行自定义通配符表达式验证(来自:AngularJS和过滤器的高级表单验证):

<form novalidate="">  
   <input type="text" id="name" name="name" ng-model="newPerson.name"
      ensure-expression="(persons | filter:{name: newPerson.name}:true).length !== 1">
   <!-- or in your case:-->
   <input type="text" id="fruitName" name="fruitName" ng-model="data.fruitName"
      ensure-expression="(blacklist | filter:{fruitName: data.fruitName}:true).length !== 1">
</form>
app.directive('ensureExpression', ['$http', '$parse', function($http, $parse) {
    return {
        require: 'ngModel',
        link: function(scope, ele, attrs, ngModelController) {
            scope.$watch(attrs.ngModel, function(value) {
                var booleanResult = $parse(attrs.ensureExpression)(scope);
                ngModelController.$setValidity('expression', booleanResult);
            });
        }
    };
}]);

jsFiddle演示(支持表达式命名和多个表达式)

它类似于ui-validate,但你不需要特定于作用域的验证函数(这是通用的),当然你也不需要ui。Utils这样。

你可以使用Angular-Validator。

示例:使用函数验证字段

<input  type = "text"
    name = "firstName"
    ng-model = "person.firstName"
    validator = "myCustomValidationFunction(form.firstName)">

在控制器中,你会看到

$scope.myCustomValidationFunction = function(firstName){ 
   if ( firstName === "John") {
       return true;
    }

你也可以这样做:

<input  type = "text"
        name = "firstName"
        ng-model = "person.firstName"
        validator = "'!(field1 && field2 && field3)'"
        invalid-message = "'This field is required'">

(其中field1、field2和field3是作用域变量。你可能还想检查字段是否不等于空字符串)

如果字段没有通过验证器,那么该字段将被标记为无效,用户将无法提交表单。

更多用例和示例请参见:https://github.com/turinggroup/angular-validator

免责声明:我是Angular-Validator的作者