我真的很喜欢如何埃里克·巴纳德的淘汰赛验证LIB与观测相集成,允许分组,及提供自定义验证可插拔(包括即时验证)。 有一对夫妇的地方,它可以更灵活UX /友好的,但总体来说是合理的证据充分的...... 除了,国际海事组织,当涉及到异步验证 。
今天我跟这个搏斗了几个小时做一个搜索和之前降落在此 。 我觉得我有同样的问题/疑问原作者,但同意,目前还不清楚到底是什么DUXA问了。 我想带来的问题更多的关注,所以我也问在这里。
function MyViewModel() {
var self = this;
self.nestedModel1.prop1 = ko.observable().extend({
required: { message: 'Model1 Prop1 is required.' },
maxLength: {
params: 140,
message: '{0} characters max please.'
}
});
self.nestedModel2.prop2 = ko.observable().extend({
required: { message: 'Model2 Prop2 is required' },
validation: {
async: true,
validator: function(val, opts, callback) {
$.ajax({ // BREAKPOINT #1
url: '/validate-remote',
type: 'POST',
data: { ...some data... }
})
.success(function(response) {
if (response == true) callback(true); // BREAKPOINT #2
else callback(false);
});
},
message: 'Sorry, server says no :('
}
});
}
ko.validation.group(self.nestedModel1);
ko.validation.group(self.nestedModel2);
一对夫妇约上面的代码的注释:有2个独立的验证组,一组用于每个嵌套模型。 嵌套模型#1不具有异步验证器,和嵌套模型#2具有两个同步(必需)和一个异步。 异步调用服务器呼叫来验证输入。 当服务器响应时, callback
参数是用来告诉ko.validation
用户的输入是否是好还是坏。 如果你把上线断点指示和触发验证使用已知的无效值,你结束了一个无限循环了AJAX success
功能使validator
功能再次调用。 我破解打开ko.validation
源代码,看看发生了什么事情。
ko.validation.validateObservable = function(observable) {
// set up variables & check for conditions (omitted for brevity)
// loop over validators attached to the observable
for (; i < len; i++) {
if (rule['async'] || ctx['async']) {
//run async validation
validateAsync();
} else {
//run normal sync validation
if (!validateSync(observable, rule, ctx)) {
return false; //break out of the loop
}
}
}
//finally if we got this far, make the observable valid again!
observable.error = null;
observable.__valid__(true);
return true;
}
该功能是在附接至所述用户输入可观察的预订链,使得当其值改变时,新的值将被验证。 该算法遍历附接到输入每个校验和执行取决于验证是否是异步或不独立的功能。 如果同步验证失败,循环被打破,整个validateObservable
函数退出。 如果所有的同步验证通过,最后3行执行,实质上是告诉ko.validation
此输入是有效的。 该__valid__
库中的函数如下所示:
//the true holder of whether the observable is valid or not
observable.__valid__ = ko.observable(true);
有两件事情,从这个带走: __valid__
是可观察到的,它被设置为true
后validateAsync
函数退出。 现在,让我们来看看validateAsync
:
function validateAsync(observable, rule, ctx) {
observable.isValidating(true);
var callBack = function (valObj) {
var isValid = false,
msg = '';
if (!observable.__valid__()) {
// omitted for brevity, __valid__ is true in this scneario
}
//we were handed back a complex object
if (valObj['message']) {
isValid = valObj.isValid;
msg = valObj.message;
} else {
isValid = valObj;
}
if (!isValid) {
//not valid, so format the error message...
observable.error = ko.validation.formatMessage(...);
observable.__valid__(isValid);
}
// tell it that we're done
observable.isValidating(false);
};
//fire the validator and hand it the callback
rule.validator(observable(), ctx.params || true, callBack);
}
需要注意的是之前仅此函数的第一个和最后一个行执行的是很重要的ko.validation.validateObservable
设置__valid__
可观察到真实和退出。 该callBack
函数就是被作为第三个参数的异步传递validator
中声明功能MyViewModel
。 出现这种情况然而之前,一个isValidating
观察到的用户被调用,以通知异步验证已经开始。 当服务器调用完成后,调用回调函数(在这种情况下只是路过true或false)。
现在,这里就是为什么在断点MyViewModel
当服务器端验证失败,也引起无限乒乓循环:在callBack
上述功能,请注意如何__valid__
在验证失败时可观察到的设置为false。 这里是发生了什么:
- 无效的用户输入改变
nestedModel2.prop2
观察到。 - 该
ko.validation.validateObservable
通过这种变化的通知订阅。 - 该
validateAsync
函数被调用。 - 自定义验证异步调用,它提交一个异步
$.ajax
调用服务器并退出。 - 该
ko.validation.validateObservable
设置__valid__
可观察到true
和退出 。 - 服务器返回一个无效的响应,和
callBack(false)
被执行。 - 该
callBack
函数设置__valid__
给false
。 - 所述
ko.validation.validateObservable
被通知改变到的__valid__
观察到的(callBack
改变了它从true
到false
)这基本上重复上面的步骤2。 - 步骤3,4和5的上方被重复。
- 由于可观察到的值没有改变,则服务器返回另一个无效的响应,触发步骤6,7,8,和9以上。
- 我们有自己乒乓球比赛。
因此,它似乎是一个问题是, ko.validation.validateObservable
订阅处理器是听不只是用户的输入值的变化,也改变了其嵌套__valid__
观察到。 这是一个错误,还是我做错了什么?
次要问题
您可以从看到ko.validation
源上面异步验证,用户的输入值,而服务器验证它被视为有效。 正因为如此,在调用nestedModel2.isValid()
不能为“真理”依赖。 相反,它看起来我们必须使用isValidating
钩创建订阅到异步验证,只有做这样的决定,他们通知的值之后, false
。 这是设计? 相比于库中,这家似乎是最直觉,因为非异步验证没有一个isValidating
订阅,并可以依靠.isValid()
说实话。 这也是由设计,还是我在这里做得不对呢?