如何向AngularJS表单添加自定义验证?
我有一个带有输入字段和验证设置的表单,通过添加如何向AngularJS表单添加自定义验证?,angularjs,Angularjs,我有一个带有输入字段和验证设置的表单,通过添加required属性等。但对于某些字段,我需要做一些额外的验证。我如何“点击”到FormController控制的验证 自定义验证可能类似于“如果填写了这3个字段,则此字段是必需的,并且需要以特定方式格式化” FormController.$setValidity中有一个方法,但它看起来不像公共API,所以我不想使用它。创建自定义指令并使用NgModelController看起来像是另一个选项,但基本上需要我为每个自定义验证规则创建一个指令,这是我不
required
属性等。但对于某些字段,我需要做一些额外的验证。我如何“点击”到FormController
控制的验证
自定义验证可能类似于“如果填写了这3个字段,则此字段是必需的,并且需要以特定方式格式化”
FormController.$setValidity
中有一个方法,但它看起来不像公共API,所以我不想使用它。创建自定义指令并使用NgModelController
看起来像是另一个选项,但基本上需要我为每个自定义验证规则创建一个指令,这是我不想要的
实际上,在最简单的场景中,将控制器中的字段标记为无效(同时保持
FormController
同步)可能是我完成工作所需要的,但我不知道如何做到这一点。Angular UI的项目包括一个UI验证指令,它可能会帮助您完成这项工作。它允许您指定一个要调用的函数来执行验证
查看演示页面:,向下搜索验证标题
从演示页面:
<input ng-model="email" ui-validate='{blacklist : notBlackListed}'>
<span ng-show='form.email.$error.blacklist'>This e-mail is black-listed!</span>
编辑:在下面添加有关ngMessages(>=1.3.X)的信息。 标准表单验证消息(1.0.X及以上版本) 由于这是Google“Angular Form Validation”的顶级结果之一,目前,我想为来自那里的任何人添加另一个答案 FormController中有一个方法。$setValidity,但它看起来不像公共API,所以我不想使用它 这是“公开的”,不用担心。使用它。这就是它的目的。如果不打算使用它,Angular开发人员会在关闭时将其私有化 要进行自定义验证,如果您不想像其他答案建议的那样使用Angular UI,只需滚动您自己的验证指令即可
app.directive('blacklist',function(){
返回{
要求:'ngModel',
链接:功能(范围、要素、属性、ngModel){
var blacklist=attr.blacklist.split(',');
//对于DOM->模型验证
ngModel.$parsers.unshift(函数(值){
var valid=blacklist.indexOf(值)=-1;
ngModel.$setValidity(“黑名单”,有效);
返回有效?值:未定义;
});
//用于模型->DOM验证
ngModel.$formatters.unshift(函数(值){
ngModel.$setValidity('blacklist',blacklist.indexOf(value)=-1);
返回值;
});
}
};
});
下面是一些示例用法:
<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 />
短语“{data.fruitName}}”被列入黑名单
必修的
提交
注意:在1.2.X中,如果ng show
替换上述ng show
,则可能更倾向于使用ng
这是一份必须的文件
此外,我还写了一些关于这个主题的博客文章,内容更加详细:
编辑:在1.3.X中使用ngMessages
您现在可以使用ngMessages模块而不是ngShow来显示错误消息。它实际上可以处理任何东西,不一定是错误消息,但以下是一些基本信息:
包括
在模块声明中参考ngMessages
:
var-app=angular.module('myApp',['ngMessages']);
添加适当的标记:
必修的
无效电子邮件
在上面的标记中,ng message=“personForm.email.$error”
基本上指定了ng message
子指令的上下文。然后ng message=“required”
和ng message=“email”
指定要查看的上下文的属性最重要的是,它们还指定了将其签入的顺序。它在列表中找到的第一个“truthy”将获胜,它将显示该消息,而不会显示其他消息
和一个您可以使用验证场景所需的ng(“如果填写了这3个字段,则此字段为必填字段”:
@synergetic我认为@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);
下面是一种在表单(from:)中执行自定义通配符表达式验证的酷方法:
app.directive('ensureExpression',['$http','$parse',function($http,$parse){
返回{
要求:'ngModel',
链接:功能(范围、元素、属性、ngModelController){
范围$watch(attrs.ngModel,函数(值){
var booleansult=$parse(attrs.ensureExpression)(范围);
ngModelController.$setValidity('expression',booleansult);
});
}
};
}]);
(支持表达式命名和多个表达式)
它类似于“ui验证”
,但您不需要特定于范围的验证功能(这通常是有效的),当然,您也不需要这样的ui.utils。您可以使用
示例:使用函数验证字段
<input type = "text"
name = "firstName"
ng-model = "person.firstName"
validator = "myCustomValidationFunction(form.firstName)">
您也可以这样做:
<input type = "text"
name = "firstName"
ng-model = "person.firstName"
validator = "'!(field1 && field2 && field3)'"
invalid-message = "'This field is required'">
(其中field1、field2和field3是范围变量。您可能还需要检查字段是否不等于空字符串)
如果该字段未通过验证程序
,则该字段将被标记为无效,用户将无法提交表单
有关更多用例和示例,请参阅:
免责声明:我是Angular Validator的作者更新:
<input type = "text"
name = "firstName"
ng-model = "person.firstName"
validator = "'!(field1 && field2 && field3)'"
invalid-message = "'This field is required'">
以前指令的改进和简化版本(一个而不是两个),具有相同的功能:
.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 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" />
确保在以下情况下执行表达式
以验证模型
<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 />
.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" />
.directive('invalidIf', [function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
var argsObject = scope.$eval(attrs.invalidIf);
if (!angular.isObject(argsObject)) {
argsObject = { invalidIf: attrs.invalidIf };
}
for (var validationKey in argsObject) {
scope.$watch(argsObject[validationKey], function (newVal) {
ctrl.$setValidity(validationKey, !newVal);
});
}
}
};
}]);
<input ng-model="foo" invalid-if="{fooIsGreaterThanBar: 'foo > bar',
fooEqualsSomeFuncResult: 'foo == someFuncResult()'}/>
<input ng-model="foo" invalid-if="foo > bar"/>
<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
}
};
});
<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;
});
}
};
}
]);
<input type="text" name="field4" ng-model="field4"
validity="eval"
validity-eval="!(field1 && field2 && field3 && !field4)"
validity-message-eval="This field is required">
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;
});
};
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;
});
}
};
});