我刚开始创建一个表单验证器,遇到了一个令人费解的问题。如果我要验证一个简单的字段(比如密码),我可以单独在客户端执行此操作(并不是说我不会在服务器上验证它)。我的意思是我可以在客户端机器上进行验证而无需任何外部检查。
如果我要验证一个更复杂的字段(用户名),这需要外部检查。例如,在注册表中,我想验证用户名(确保它不存在)。为此,我必须进行 ajax 调用。这让事情变得有点复杂。检查下面的代码。
FormValidator.prototype.validate = function validateForm() {
this.errors = {};
for (var fieldName in this.fields) {
var field = this.fields[fieldName];
if (field.hasOwnProperty("required") && field.required && field.elem.value.length == 0) {
this.addError(fieldName, "This field is required.");
break;
}
if (field.hasOwnProperty("minLength") && field.elem.value.length < field.minLength) {
this.addError(fieldName, "Input length should not be less than " + field.minLength + " characters.");
break;
}
if (field.hasOwnProperty("maxLength") && field.elem.value.length > field.maxLength) {
this.addError(fieldName, "Input length should not be greater than" + field.maxLength + " characters.");
break;
}
if (field.hasOwnProperty("ajax")) {
// FormValidator can't possibly know what the call will return, so we can't add the error here
// it has to be done manually
field.ajax(this, field, fieldName);
}
}
if (this.errors.length != 0) {
// warn the user
console.log(this.errors);
}
};
var fv = new FormValidator(document.forms[0]);
fv.addField("login_name", {
type : "text",
minLength : 4,
maxLength : 32,
required : true,
ajax : function (fv, field, fieldName) {
ajax("http://localhost/surec/scripts/user_check.php?field=login_name&value=" + field.elem.value, {
success : function () {
var response = JSON.parse(this.response);
// manually adding the error
if (!response.error && response.exists) {
fv.addError(fieldName, "This username is taken.");
}
},
// async: false,
});
},
});
// called on form submit
// fv.validate();
调用 fv.validate()
的那一刻(假设用户输入了一个被占用的用户名),validate()
不会做任何事情来警告用户,因为ajax 调用是异步的。错误检查完成后 if (this.errors.length != 0) {
,错误将为空。它会在 ajax 调用完成时填充,然后为时已晚。
要解决此问题,我可以使 ajax 调用同步。这解决了问题,但我不确定是否使用同步调用。这种方法是否有效,或者是否有我可以采用的替代方法?
更新:我已经开始研究 Promise,我想我已经掌握了它的窍门。我已经让它工作到一定程度,所以我仍然需要一些帮助。
我正在尝试做的事情的图形描述是这样的:
我已经创建了一个异步循环函数,我将使用它来循环字段:
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
以及验证函数的当前状态:
FormValidator.prototype.validate = async function validateForm() {
this.errors = {};
var self = this;
await asyncForEach(self.fields.keys(), async function (fieldName) {
var field = self.fields[fieldName];
if (field.hasOwnProperty("required") && field.required && field.elem.value.length == 0) {
self.addError(fieldName, "This field is required.");
// break;
}
if (field.hasOwnProperty("minLength") && field.elem.value.length < field.minLength) {
self.addError(fieldName, "Input length should not be less than " + field.minLength + " characters.");
// break;
}
if (field.hasOwnProperty("maxLength") && field.elem.value.length > field.maxLength) {
self.addError(fieldName, "Input length should not be greater than " + field.maxLength + " characters.");
// break;
}
if (field.hasOwnProperty("ajax")) {
// FormValidator can't possibly know what the call will return, so we can't add the error here
// it has to be done manually
await field.ajax(self, field, fieldName);
}
});
if (self.errors.length() != 0) {
// warn the user
console.log("errors: ", self.errors);
}
};
这似乎有效(在测试用例中)。见下文。我没有使用 ajax 函数,而是伪造了它(使用 1 秒延迟)。 console.log("errors: ", self.errors);
中的 fv.validate()
在外部检查(假 ajax)完成后运行(延迟 1 秒)。
var fv = new FormValidator(document.forms[0]);
fv.addField("login_name", {
type : "text",
minLength : 4,
maxLength : 32,
required : true,
ajax : async function (fv, field, fieldName) {
// assume delay is ajax
await delay(1000);
// and on success (and login_name collision) we add an error
fv.addError(fieldName, "This username is taken.");
},
});
var delay = (ms) => new Promise(r => setTimeout(r, ms));
fv.validate();
现在,我需要重写外部检查方法 (ajax
) 并使其与这段代码一起工作。我已经尝试了一些组合(可能是废话,使用试错),但无法使其工作。我应该如何进行?
FormValidator.js (GitHub repo )
最佳答案
这是一种可能的 promise 实现。这是一个简化的示例,只关注管理一组错误,其中一个是 ajax 调用的结果
// errors is an array of promises
const errors = ["Too long"]
const remoteErrorCheck = $.ajax({type:"GET", url:'https://api.stackexchange.com/2.2/info?site=stackoverflow'}).then(function(data){
// here you have access to the result of ajax request, inside data
return Promise.resolve("error or ok")
// you want to return a promise to put in the array of promises
})
// now put the promise from the ajax request into the array of promises
errors.push(remoteErrorCheck)
// when all the promises are resolved, then do something with the results
Promise.all(errors).then((a)=>{
console.log(a)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
请注意,Promise.all
在执行之前等待 ajax 完成。 Promise.all
将字符串视为已解决的 promise 。
因为 remoteErrorCheck
已经有一个 .then
也被执行并且因为它返回一个 promise ,Promise of Promise
被压缩成只是一个 promise ,这就是为什么您可以访问错误数组中的 error 或 ok
字符串
这需要根据您的情况进行调整(对象而不是字符串,then
中的验证函数应该从外部传递,...)但它应该是一个很好的起点
关于javascript - 在提交表单之前使用 ajax 验证字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50970095/