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

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

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

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


当前回答

调用服务器的自定义验证

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

其他回答

在这篇文章中有一些很好的例子和注解,但它们并不是我想要的。我的方法:angular-validity——一个基于承诺的异步验证库,带有可选的Bootstrap样式。

OP用例的角度有效性解决方案可能是这样的:

<input  type="text" name="field4" ng-model="field4"
        validity="eval"
        validity-eval="!(field1 && field2 && field3 && !field4)"
        validity-message-eval="This field is required">

这是小提琴,如果你想玩的话。该库在GitHub上可用,有详细的文档和大量的现场演示。

你可以在你的验证场景中使用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>

@ synergy我认为@blesh应该把函数验证如下

function validate(value) {
    var valid = blacklist.indexOf(value) === -1;
    ngModel.$setValidity('blacklist', valid);
    return valid ? value : undefined;
}

ngModel.$formatters.unshift(validate);
ngModel.$parsers.unshift(validate);

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;
  };
}

调用服务器的自定义验证

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