为什么添加额外的 AngularJS 验证指令会导致 $async Validators 多次 运行?
Why does adding additional AngularJS validation directives cause $asyncValidators to run multiple times?
为什么添加额外的 AngularJS 验证指令会导致页面加载时 $asyncValidators
到 运行 多次?
我创建了一个实现 $asyncValidators 的自定义指令。这是该自定义指令的基本结构:
myApp.directive('userSaved',['$q','userLookup',function($q, userLookup){
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ctrl){
ctrl.$asyncValidators.userSaved = function(modelValue, viewValue) {
// do stuff
}
}
}
}]);
控制器像这样初始化 tailNumber
模型值:
$scope.tailNumber = 'N33221';
这是 html,其中 user-saved
指令在页面加载时 运行s 3 次:
<input ng-model="tailNumber" name="tailNumber" user-saved
ng-minlength="2" ng-pattern="/^[A-z][a-zA-Z0-9]*$/" >
当我删除 ng-minlength="2"
时,user-saved
指令在页面加载时 运行s 两次(2 次)。这是删除了 ng-minlength="2"
的 html:
<input ng-model="tailNumber" name="tailNumber" user-saved
ng-pattern="/^[A-z][a-zA-Z0-9]*$/" >
当我删除 ng-pattern="/^[A-z][a-zA-Z0-9]*$/"
时,user-saved
指令只有 运行s 1 次 。这是删除 ng-pattern="/^[A-z][a-zA-Z0-9]*$/"
后的 html
<input ng-model="tailNumber" name="tailNumber" user-saved >
为什么我的函数向 $asyncValidators
运行 注册附加到表单元素的每个附加 ng 验证器需要额外的时间?
我的自定义指令是一个昂贵的 $http
调用,我更喜欢我的自定义指令在页面加载时只 运行 一次。是否可以使用所有这些 ng 验证器并且在页面加载时只 运行 宁我的异步验证器函数一次而不是 3 次?
这是因为 ngMaxlength
、ngPattern
等验证指令通过调用 ngModelController.$validate()
.
来调用初始验证周期
这会导致所有验证指令运行它们的验证逻辑,包括异步验证器。
防止冗余 $http
调用的一种方法是缓存每个输入的验证结果。
实际上我花了一段时间才弄明白这一点。如 this post 中所述,Angular 验证器会触发额外的验证。我决定不反对这种行为,而是解决它,转而使用解析器和格式化程序:
myApp.directive('userSaved',['$q','dataservice',function($q, dataservice){
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ctrl){
ctrl.$parsers.unshift(checkUserSaved);
ctrl.$formatters.unshift(checkUserSaved);
function checkUserSaved(value){
ctrl.$setValidity("usersaved") // the absence of the state parameter sets $pending to true for this validation
dataservice.getUserSaved(value).then(function(response){
var userIsSaved = (response === true);
ctrl.$setValidity("usersaved", userIsSaved); // the presence of the state parameter removes $pending for this validation
return userIsSaved ? value : undefined;
});
return value;
}
}
}
}]);
作为参考,您可能还想查看 Angular docs
编辑
经进一步调查,似乎在 ng-pattern 的情况下,仅当正则表达式从字符串转换时才会触发额外的验证。
直接传递正则表达式:
<div ng-pattern="/^[0-9]$/" user-saved></div>
解决了我在使用验证器管道时遇到的问题。
我听从了@New Dev 的建议并实现了一个简单的缓存例程,它很好地满足了我的要求,这就是我想出的..
link: function (scope, element, attributes, ngModel) {
var cache = {};
ngModel.$asyncValidators.validateValue = function (modelValue) {
if (modelValue && cache[modelValue] !== true) {
return MyHttpService.validateValue(modelValue).then(function (resolved) {
cache[modelValue] = true; // cache
return resolved;
}, function(rejected) {
cache[modelValue] = false;
return $q.reject(rejected);
});
} else {
return $q.resolve("OK");
}
};
}
为什么添加额外的 AngularJS 验证指令会导致页面加载时 $asyncValidators
到 运行 多次?
我创建了一个实现 $asyncValidators 的自定义指令。这是该自定义指令的基本结构:
myApp.directive('userSaved',['$q','userLookup',function($q, userLookup){
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ctrl){
ctrl.$asyncValidators.userSaved = function(modelValue, viewValue) {
// do stuff
}
}
}
}]);
控制器像这样初始化 tailNumber
模型值:
$scope.tailNumber = 'N33221';
这是 html,其中 user-saved
指令在页面加载时 运行s 3 次:
<input ng-model="tailNumber" name="tailNumber" user-saved
ng-minlength="2" ng-pattern="/^[A-z][a-zA-Z0-9]*$/" >
当我删除 ng-minlength="2"
时,user-saved
指令在页面加载时 运行s 两次(2 次)。这是删除了 ng-minlength="2"
的 html:
<input ng-model="tailNumber" name="tailNumber" user-saved
ng-pattern="/^[A-z][a-zA-Z0-9]*$/" >
当我删除 ng-pattern="/^[A-z][a-zA-Z0-9]*$/"
时,user-saved
指令只有 运行s 1 次 。这是删除 ng-pattern="/^[A-z][a-zA-Z0-9]*$/"
<input ng-model="tailNumber" name="tailNumber" user-saved >
为什么我的函数向 $asyncValidators
运行 注册附加到表单元素的每个附加 ng 验证器需要额外的时间?
我的自定义指令是一个昂贵的 $http
调用,我更喜欢我的自定义指令在页面加载时只 运行 一次。是否可以使用所有这些 ng 验证器并且在页面加载时只 运行 宁我的异步验证器函数一次而不是 3 次?
这是因为 ngMaxlength
、ngPattern
等验证指令通过调用 ngModelController.$validate()
.
这会导致所有验证指令运行它们的验证逻辑,包括异步验证器。
防止冗余 $http
调用的一种方法是缓存每个输入的验证结果。
实际上我花了一段时间才弄明白这一点。如 this post 中所述,Angular 验证器会触发额外的验证。我决定不反对这种行为,而是解决它,转而使用解析器和格式化程序:
myApp.directive('userSaved',['$q','dataservice',function($q, dataservice){
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ctrl){
ctrl.$parsers.unshift(checkUserSaved);
ctrl.$formatters.unshift(checkUserSaved);
function checkUserSaved(value){
ctrl.$setValidity("usersaved") // the absence of the state parameter sets $pending to true for this validation
dataservice.getUserSaved(value).then(function(response){
var userIsSaved = (response === true);
ctrl.$setValidity("usersaved", userIsSaved); // the presence of the state parameter removes $pending for this validation
return userIsSaved ? value : undefined;
});
return value;
}
}
}
}]);
作为参考,您可能还想查看 Angular docs
编辑
经进一步调查,似乎在 ng-pattern 的情况下,仅当正则表达式从字符串转换时才会触发额外的验证。
直接传递正则表达式:
<div ng-pattern="/^[0-9]$/" user-saved></div>
解决了我在使用验证器管道时遇到的问题。
我听从了@New Dev 的建议并实现了一个简单的缓存例程,它很好地满足了我的要求,这就是我想出的..
link: function (scope, element, attributes, ngModel) {
var cache = {};
ngModel.$asyncValidators.validateValue = function (modelValue) {
if (modelValue && cache[modelValue] !== true) {
return MyHttpService.validateValue(modelValue).then(function (resolved) {
cache[modelValue] = true; // cache
return resolved;
}, function(rejected) {
cache[modelValue] = false;
return $q.reject(rejected);
});
} else {
return $q.resolve("OK");
}
};
}