我在表单上有一个包含大量验证的字段。
首先,我将其结构化为多个指令,每个指令都有自己的错误消息。
然而,验证使用后端异步调用,因此突然对于一个字段我正在为同一个数据服务进行5次http调用。我想弄清楚如何更有效地写这个。
我想知道是否有可能在$async
之后有一个调用dataservice的$validators
验证器和第一个异步函数内的多个常规.then
。我试验过这个,但它似乎根本没有达到嵌套$validators
。
我还试图在服务中进行一次调用,但是当字段上的modelValue发生更改时,我不知道如何更新它,并因此将信息传递给相应的验证指令。我可以将此作为服务中的异步验证,并将响应附加到要查找的指令的范围吗?
TLDR;
如何进行一次http调用并根据返回的数据执行多次验证检查,每次都有自己的错误?
例如
我有四个看起来像这样的指令:
angular.module('validationForField').directive('po', ['$q', '$sce', '$timeout', 'myService', function ($q, $sce, $timeout, myService) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ctrl, ngModel) {
ctrl.$asyncValidators.validateField = function (modelValue) {
var def = $q.defer();
myService.httpcall(modelValue)
.then(function (response, modelValue) {
if (response.data.status === "Error") {
return def.reject();
}
def.resolve();
}).catch(function(){
def.reject();
});
return def.promise;
}
}
}
}]);
每个人都有不同的数据分析,以返回不同的错误消息。每个人都调用myService.httpcall,这最终是多余的,因为他们都获得了相同的数据。
我正在尝试
angular.module('validationForField').directive('po', ['$q', '$sce', '$timeout', 'myService', function ($q, $sce, $timeout, myService) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ctrl, ngModel) {
ctrl.$asyncValidators.validateField = function (modelValue) {
var def = $q.defer();
myService.httpcall(modelValue)
.then(function (response, modelValue) {
if (response.data.status === "Error") {
return def.reject();
}
ctrl.$validators.checkStatus = function (response) {
if (response.data.data.status === "10"){
return false
}
ctrl.$validators.checkPermissions = function (response) {
return response.data.data.permission){
}
def.resolve();
}).catch(function(){
def.reject();
});
return def.promise;
}
}
}
}]);
通过这种方式,主要的异步验证器是关于http调用是否成功,以及内部$ validators在返回时使用该数据
答案 0 :(得分:1)
我假设后端服务接受一个值(要验证的字段的值)并返回所有验证的单个响应,例如:
// true would mean valid, string would mean invalid with the given error:
{
businessRuleOne: true,
businessRuleTwo: "The format is incorrect",
...
}
我相信解决方案是在缓存承诺的服务中执行HTTP调用;异步验证器调用服务并检索它们返回的相同promise。一些带内联解释的示例代码:
// the service:
app.service('myService', function($http, $q) {
// cache the requests, keyed by the model value
var requestMap = {};
this.httpcall = function(modelValue) {
// if cached, return that (and do not make extra call)
if( requestMap[modelValue] ) {
return requestMap[modelValue];
}
// if not cahced, make the call...
var promise = $http.get('....');
// ...cache it...
requestMap[modelValue] = promise;
// ...and remember to remove it from cache when done
promise.finally(function() {
delete requestMap[modelValue];
});
return promise;
};
});
现在可以完全按照发布的方式实现异步验证器。调用myService.httpcall(modelValue)
只会在第一次调用时调用远程服务,其余的将重用缓存的promise。
还有两点:(1)这种技术称为memoization。它由许多库实现,例如lodash,您可以使用它们来保持myservice.httpcall()
清洁。 (2)您不需要异步验证器的额外承诺,例如:
angular.module('validationForField').directive('po', ['$q', '$sce', '$timeout', 'myService', function ($q, $sce, $timeout, myService) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ctrl, ngModel) {
ctrl.$asyncValidators.validateField = function (modelValue) {
return myService.httpcall(modelValue)
.then(function (response) {
if (response.data.status === "Error") {
return $q.reject();
}
return response;
});
}
}
}
}]);