[英]jQuery each with ajax call will continue before it's finished
我有一些jQuery,它使用每个循环来遍历Symfony 3 CRM上重复表格字段中输入的值。 有一个$.post
,它将输入的值发送到检查数据库中是否存在重复项的函数,如果是重复项,则会向数组中添加某些内容,否则将添加空白值以表明不是重复项。 完成这些操作后,它将检查最终数组,并将所有错误添加到错误块以显示给用户。
但是,数组似乎总是空白,我相信它是因为它正在运行显示错误的代码,然后才真正完成响应。
这是我的代码:
$('#puppy_form').on('submit', function() {
var bitch_errors = [];
var dog_errors = [];
// NOTE: Bitch and dog names need to be checked differently so we know which error is assigned to which input
$('.check_bitch_name').each( function(i, obj) {
// need to check each name for validity and duplication.
var entered_bitch_name = obj.value;
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(entered_bitch_name)) {
bitch_errors[i+1] = "invalid";
} else {
// now to check for duplicates
$.post('/check-puppy-name', { name: entered_bitch_name }
).done(function (response) {
if(response == 'duplicate') {
bitch_errors[i+1] = "duplicate";
} else {
bitch_errors[i+1] = "";
}
});
}
});
$('.check_dog_name').each( function(i, obj) {
// need to check each name for validity and duplication.
var entered_dog_name = obj.value;
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(entered_dog_name)) {
dog_errors[i+1] = "invalid";
} else {
// now to check for duplicates
$.post('/check-puppy-name', { name: entered_dog_name }
).done(function (response) {
if(response == 'duplicate') {
dog_errors[i+1] = "duplicate";
} else {
dog_errors[i+1] = "";
}
});
}
});
if(count(bitch_errors) == 0 && count(dog_errors) == 0) {
return true;
}
// loop through the errors and assign them to the correct input
$.each( bitch_errors, function( key, value ) {
if (value == "invalid") {
$('input[name="bitch_name['+key+']"]').parent().addClass('has-error');
$('input[name="bitch_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters');
return false;
} else if(value == "duplicate") {
$('input[name="bitch_name['+key+']"]').parent().addClass('has-error');
$('input[name="bitch_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken');
return false;
}
});
$.each( dog_errors, function( key, value ) {
if(value != "") {
if (value == "invalid") {
$('input[name="dog_name['+key+']"]').parent().addClass('has-error');
$('input[name="dog_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters');
return false;
} else if(value == "duplicate") {
$('input[name="dog_name['+key+']"]').parent().addClass('has-error');
$('input[name="dog_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken');
return false;
}
}
});
return false;
});
基本上,它首先检查输入的名称是否有效,然后过帐并检查是否存在重复。 问题是,即使它进行了有效性检查(并相应地输出错误),它也似乎忽略了重复检查,并在它还没有返回第一个响应之前就继续执行。
我如何确保在完成检查之前完成检查并将错误添加到表单? 我尝试了其他解决方案,包括尝试在jQuery中实现$.when
功能,但我不太了解如何使其工作。 任何帮助表示赞赏。
首先,编写返回异步答应给你一个值, 一个狗功能:
function checkDog(name) {
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(name)) {
return $.Deferred().resolve("invalid");
} else {
return $.post('/check-puppy-name', { name: name } )
.then(function (response) {
if (response === 'duplicate') {
return 'duplicate';
} else {
return '';
}
});
}
}
然后,您可以编写一个处理多只狗的代码,同时返回一个承诺(只有在检查完每只狗之后,它才会被解决):
function checkDogs(array) {
return $.when.apply($, array.map(checkDog));
}
注意,还没有与DOM相关的代码。 现在,您可以编写一个函数,该函数从一堆DOM输入中获取值并以数组形式返回它们:
function getInputValues($selector) {
return $selector.get().map(function(el) {
return el.value;
});
}
因此,现在( submit
)您可以检查您的两组输入,然后最后在两个输入都可用时,您可以检查结果并更新DOM:
$('#puppy_form').on('submit', function() {
var bitch_names = getInputValues($('.check_bitch_name'));
var dog_names = getInputValues($('.check_dog_name'));
var bitch_promises = checkDogs(bitch_names);
var dog_promises = checkDogs(dog_names);
$.when(bitch_promises, dog_promises).then(function(bitch_errors, dog_errors) {
// update the DOM based on the passed arrays
...
});
});
没错,ajax调用就像它们的名字说的那样异步。 因此,您只能依靠.done
函数。 一个简单的解决方案是在母犬和狗的开头初始化一个计数器变量,然后在完成的函数中将其递减直到其达到零。 然后,也在完成函数中,放置一个if
来调用错误数组的验证。 这是未测试的代码,以显示我的意思:
$('#puppy_form').on('submit', function() {
/*
here you get the initial count for bitches and dogs
*/
var bitch_count = $('.check_bitch_name').length;
var dog_count = $('.check_dog_name').length;
var bitch_errors = [];
var dog_errors = [];
// NOTE: Bitch and dog names need to be checked differently so we know which error is assigned to which input
$('.check_bitch_name').each( function(i, obj) {
// need to check each name for validity and duplication.
var entered_bitch_name = obj.value;
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(entered_bitch_name)) {
bitch_errors[i+1] = "invalid";
} else {
// now to check for duplicates
$.post('/check-puppy-name', { name: entered_bitch_name }
).done(function (response) {
if(response == 'duplicate') {
bitch_errors[i+1] = "duplicate";
} else {
bitch_errors[i+1] = "";
}
/*
now on every checked name you decrement the counter
and if both counters reach zero you can be sure you
checked all and only now you call your validation
*/
bitch_count--;
if(bitch_count === 0 && dog_count === 0) {
return validateErrors();
}
});
}
});
$('.check_dog_name').each( function(i, obj) {
// need to check each name for validity and duplication.
var entered_dog_name = obj.value;
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(entered_dog_name)) {
dog_errors[i+1] = "invalid";
} else {
// now to check for duplicates
$.post('/check-puppy-name', { name: entered_dog_name }
).done(function (response) {
if(response == 'duplicate') {
dog_errors[i+1] = "duplicate";
} else {
dog_errors[i+1] = "";
}
/*
same here
*/
dog_count--;
if(bitch_count === 0 && dog_count === 0) {
return validateErrors();
}
});
}
});
}
/*
...and finally all code that should be processed after the ajax calls
*/
function validateErrors() {
if(count(bitch_errors) == 0 && count(dog_errors) == 0) {
return true;
}
// loop through the errors and assign them to the correct input
$.each( bitch_errors, function( key, value ) {
if (value == "invalid") {
$('input[name="bitch_name['+key+']"]').parent().addClass('has-error');
$('input[name="bitch_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters');
return false;
} else if(value == "duplicate") {
$('input[name="bitch_name['+key+']"]').parent().addClass('has-error');
$('input[name="bitch_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken');
return false;
}
});
$.each( dog_errors, function( key, value ) {
if(value != "") {
if (value == "invalid") {
$('input[name="dog_name['+key+']"]').parent().addClass('has-error');
$('input[name="dog_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters');
return false;
} else if(value == "duplicate") {
$('input[name="dog_name['+key+']"]').parent().addClass('has-error');
$('input[name="dog_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken');
return false;
}
}
});
return false;
});
您可以使用异步库来管理这些请求并收集结果,然后将结果传递到最终的回调中,您可以在其中处理这些请求。
我没有尝试运行此代码,但希望它能使您足够接近(如果还没有的话)。
async.parallel({
bitch_errors: function(callback) {
var bitch_errors = [];
async.forEachOf($('.check_bitch_name'), function(obj, i, cb) {
// need to check each name for validity and duplication.
var entered_bitch_name = obj.value;
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(entered_bitch_name)) {
bitch_errors[i+1] = "invalid";
cb();
} else {
// now to check for duplicates
$.post('/check-puppy-name', { name: entered_bitch_name }
).done(function (response) {
if(response == 'duplicate') {
bitch_errors[i+1] = "duplicate";
} else {
bitch_errors[i+1] = "";
}
cb();
});
}
}, function () {
callback(null, bitch_errors);
});
},
dog_errors: function(callback) {
var dog_errors = [];
async.forEachOf($('.check_dog_name'), function(obj, i, cb) {
// need to check each name for validity and duplication.
var entered_dog_name = obj.value;
var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/;
if(!pattern.test(entered_dog_name)) {
dog_errors[i+1] = "invalid";
cb();
} else {
// now to check for duplicates
$.post('/check-puppy-name', { name: entered_dog_name }
).done(function (response) {
if(response == 'duplicate') {
dog_errors[i+1] = "duplicate";
} else {
dog_errors[i+1] = "";
}
cb();
});
}
}, function () {
callback(null, dog_errors);
});
}
}, function(err, results) {
// you can now access your results like so
if(count(results.bitch_errors) == 0 && count(results.dog_errors) == 0) {
// ... rest of your code
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.