I have a page which does AJAX validation of an email before continuing on to the next page, using the HTML5 setCustomValidity() method [using the webshims library for older browsers].
我有一个页面,使用HTML5 setCustomValidity()方法(使用旧浏览器的webshims库)对电子邮件进行AJAX验证,然后继续到下一个页面。
For this to work, I set the async option to false in the $.ajax() call to make it synchronous, blocking the page pending the AJAX response, as otherwise the form submits before the ajax call returns, rendering the validation ineffectual.
为此,我在$. AJAX()调用中将async选项设置为false,使其成为同步的,并阻塞挂起AJAX响应的页面,否则表单在AJAX调用返回之前提交,导致验证无效。
<script>
function validateEmailRegistered(input) {
if (input.setCustomValidity === undefined) return;
var err = 'Email address not found';
$.ajax({
url: 'email-is-registered.php',
data: { email: input.value },
async: false,
success: function(data) {
var ok = data=='true';
input.setCustomValidity(ok ? '' : err)
}
});
}
</script>
<form method="get" action="nextpage.php">
<input name="email" id="email" type="email" required
onChange="validateEmailRegistered(this)">
<button type="submit">go</button>
<form>
I see that the async option is to be deprecated as of jQuery 1.8.
我看到异步选项将在jQuery 1.8中被弃用。
How can I achieve this blocking action without the async option?
如何在没有async选项的情况下实现这个阻塞操作?
6 个解决方案
#1
10
http://bugs.jquery.com/ticket/11013#comment:40
http://bugs.jquery.com/ticket/11013评论:40
The use of the Deferred/Promise functionality in synchronous ajax requests has been deprecated in 1.8. The $.ajax method with async: false is supported but you must use a callback parameter rather than a Promise method such as
.then
or.done
.在同步ajax请求中使用Deferred/Promise功能在1.8中已经被弃用。美元的。支持使用async: false的ajax方法,但必须使用回调参数,而不是像.then或.done这样的承诺方法。
So, if you are using the success/complete/error handlers, you can still use async:false
. More info at the jquery ticket above.
因此,如果您正在使用成功/完整/错误处理程序,您仍然可以使用async:false。更多信息请参见上面的jquery代码。
#2
2
As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the complete/success/error callbacks.
对于jQuery 1.8,不赞成在jqXHR ($.Deferred)中使用async: false;您必须使用完整/成功/错误回调。
http://api.jquery.com/jQuery.ajax/ (async section)
http://api.jquery.com/jQuery.ajax/(异步部分)
I found this a bit annoying... developers should be given the choice to make a blocking call with async: false
if its something the platform allows - why restrict it? I'd just set a timeout to minimize the impact of a hang.
我觉得这有点烦人……应该让开发人员选择使用async: false进行阻塞调用,如果平台允许的话——为什么要限制呢?我只需设置一个超时,以最小化挂起的影响。
Nonetheless, I'm using a queue now in 1.8, which is non-blocking, and works quite nicely. Sebastien Roch created a easy to use utility that allows you to queue up functions and run/pause them. https://github.com/mjward/Jquery-Async-queue
尽管如此,我现在使用的队列是1.8,它是非阻塞的,并且工作得很好。Sebastien Roch创建了一个易于使用的实用程序,允许您排队并运行/暂停函数。https://github.com/mjward/Jquery-Async-queue
queue = new $.AsyncQueue();
queue.add(function (queue) { ajaxCall1(queue); });
queue.add(function (queue) { ajaxCall2(queue); });
queue.add(function() { ajaxCall3() });
queue.run();
In the first 2 functions I pass the queue
object into the calls, here's what the calls would look like:
在前两个函数中,我将队列对象传递给调用,如下所示:
function ajaxCall1(queue) {
queue.pause();
$.ajax({
// your parameters ....
complete: function() {
// your completing steps
queue.run();
}
});
}
// similar for ajaxCall2
Notice the queue.pause();
at the beginning of each function, and queue.run()
to continue queue execution at the end of your complete
statement.
注意到queue.pause();在每个函数的开头,和queue.run()在语句结束时继续执行队列。
#3
0
I assume you will be doing full form validation on submit anyway, so perhaps it's no problem if the as-you-type email validation is interrupted, and precedence given to the form submission.
我假设您将在提交时进行完整的表单验证,因此,如果正在输入的电子邮件验证被中断,并优先于表单提交,那么可能没有问题。
I think what I'd do is abort the 'validateEmailRegistered' AJAX request when the user submits the form. Then, perform full server-side form validation as usual - including email validation.
我认为,当用户提交表单时,我将中止“validateemailregister”AJAX请求。然后,像往常一样执行完整的服务器端表单验证——包括电子邮件验证。
My understanding of as-you-type validation is that it's a nicety, not a substitute for validating the form when it is submitted. So it doesn't make sense to me for it to block the form submission.
我对as-you-type验证的理解是,它是一种精确,而不是当它提交时验证表单的替代品。所以阻止表单提交对我来说没有意义。
#4
0
If you are really set on not letting them submit the form until you have checked the email validity, start out your submit button with the disabled
attribute, then have the callback set $('form button').removeAttr('disabled');
如果你真的设置了不让他们提交表单,直到你检查了邮件的有效性,开始你的提交按钮和禁用的属性,然后有回调设置$('表单按钮').removeAttr('禁用');
That being said, I'm with the other people - just let them submit the form! Usually people get it right and you pass them right on through with no errors...
那就是说,我和其他人在一起——让他们提交表格吧!通常情况下,人们做对了,你把他们直接传递过去,没有任何错误……
#5
0
I think you need to change a bit how you it works. Don't try to achieve blocking, but embrace non-blocking.
我认为你需要改变一下你的工作方式。不要试图实现阻塞,而是拥抱非阻塞。
I would do like this: - Keep the validation on email; make it Asynchronous. When it's valid, set a flag somewhere in a variable to know it's ok. - Add a callback on the form.submit() to check whether the email is ok (with the variable) and prevent the submission if it's not.
我想这样做:-保持电子邮件的有效性;要进行异步调用。当它有效时,在变量中某处设置一个标志,以知道它是ok的。-在form.submit()上添加回调,以检查电子邮件(带有变量)是否ok,如果不是,则防止提交。
This way you can keep asynchronous call without freeze the web browser UI.
通过这种方式,您可以保持异步调用,而不必冻结web浏览器UI。
-- [edit] --
——[编辑]
This is some quick code I just wrote for the example based on what you already have.
这是我为这个示例编写的一些快速代码,它基于您已经拥有的内容。
For your information, a programming notion called "promises" (futures and deferred are other terms for it) has been invented to solve exactly the problem you have.
对于你的信息,一个叫做“承诺”的编程概念(期货和递延是它的其他术语)已经被发明来解决你的问题。
Here's an article on what it is and how to use them in JavaScript (using dojo or jQuery): http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx
这里有一篇关于它是什么以及如何在JavaScript(使用dojo或jQuery)中使用它们的文章
<script>
function validateEmailRegistered(input) {
if (input.setCustomValidity === undefined) return;
var err = 'Email address not found';
$.ajax({
url: 'email-is-registered.php',
data: { email: input.value },
success: function(data) {
var ok = data=='true';
input.setCustomValidity(ok ? '' : err);
// If the form was already submited, re-launch the check
if (form_submitted) {
input.form.submit();
}
}
});
}
var form_submitted = false;
function submitForm(form) {
// Save the user clicked on "submit"
form_submitted = true;
return checkForm(form);
}
function checkForm(form, doSubmit) {
if (doSubmit) {
form_submitted = true;
}
// If the email is not valid (it can be delayed due to asynchronous call)
if (!form.email.is_valid) {
return false;
}
return true;
}
</script>
<form method="get" action="nextpage.php" onsumbit="return submitForm(this);">
<input name="email" id="email" type="email" required
onChange="validateEmailRegistered(this)">
<button type="submit">go</button>
<form>
#6
0
You can do it asynchronously.
可以异步完成。
Create a global variable, I call it ajax_done_and_successful_flag, that you initialize to false at the beginning of the program. You will set this to true or false at various places in your Ajax functions such as your Ajax success function or your Ajax error function.
创建一个全局变量,我称之为ajax_done_and_successful_flag,在程序开始时将其初始化为false。您将在Ajax功能(如Ajax成功函数或Ajax错误函数)的不同位置设置为true或false。
Then you need to add a submit handler at the bottom of your validate function.
然后需要在validate函数的底部添加一个submit处理程序。
submitHandler: function(form) {
if (ajax_done_and_successful_flag === true) {
form.submit()
}
}
The problem is the code is not executing in a linear way.
Put a bunch of Firebug's console.log statements in your code.
Observe the sequence of execution. You will see that your
Ajax response will come back last, or whenever it feels like it.
That's why you need the submitHandler AND the global flag
to force the validate function to wait for correct Ajax
results before the form is submitted.
问题是代码不是以线性方式执行的。放一堆Firebug的控制台。代码中的日志语句。观察执行的顺序。您将看到,您的Ajax响应将在最后返回,或者在任何时候返回。这就是为什么需要submitHandler和全局标记来强制validate函数在提交表单之前等待正确的Ajax结果。
Any output to the screen from the Ajax response, needs to be done in the Ajax functions, such as the success function and the error function.
You need to write to the same location as the validate function's success/error functions.
This way the Ajax error messages blend in with the validate function's error function.
This concept may seem a bit tricky.
The idea to keep in mind is that the success and error functions in the validate function are writing to the same location as the success and error functions in the Ajax call, and that is okay, that is how it should be.
The location of my error messages is right next to where the user types the input. This creates a nice user experience that I think you are asking for.
Ajax响应向屏幕输出的任何输出都需要在Ajax函数中完成,比如success函数和error函数。您需要写入与验证函数的成功/错误函数相同的位置。这样,Ajax错误消息与validate函数的错误函数混合在一起。这个概念似乎有点棘手。要记住的是,validate函数中的success和error函数与Ajax调用中的success和error函数写入到相同的位置,这是可以的,这就是应该的。我的错误消息的位置就在用户输入输入的位置旁边。这创造了一个良好的用户体验,我认为你正在要求。
Here is my code sample. I simplified it.
这是我的代码示例。我简化它。
I am running jQuery-1.7.1
and jQuery validation plug-in 1.6
I am using Firefox 14.0.1 and I also tried it on Chrome 21.0 successfully.
我正在运行jQuery-1.7.1和jQuery验证插件1.6,我使用的是Firefox 14.0.1,我还成功地在Chrome 21.0上试用了它。
var ajax_done_and_successful_flag = false;
// Add methods
...
$.validator.addMethod("USERNAME_NOT_DUPLICATE", function (value, element) {
return this.optional(element) || validate_username_not_duplicate( );
},
"Duplicate user name.");
// validate
$(document).ready(function ( ) {
$('#register_entry_form form').validate({
rules: {
username: {
required: true,
minlength: 2,
maxlength: 20,
USERNAME_PATTERN: true,
USERNAME_NOT_DUPLICATE: true
},
...
errorPlacement: function (error, element) {
element.closest("div").find(".reg_entry_error").html(error);
},
success: function(label) {
label.text('Success!');
} ,
submitHandler: function(form) {
if (ajax_done_and_successful_flag === true ) {
form.submit();
}
}
});
});
/* validation functions*/
function validate_username_not_duplicate() {
var username_value = $('#username').val(); // whatever is typed in
$.ajax({
url: "check_duplicate_username.php",
type: "POST",
data: { username: username_value },
dataType: "text",
cache: false,
//async: false,
timeout: 5000,
error: function (jqXHR, errorType, errorMessage) {
ajax_done_and_successful_flag = false;
if ( errorType === "timeout" ) {
$('#username').closest("div").find(".reg_entry_error").html("Server timeout, try again later" );
} else if ...
},
success: function (retString, textStatus,jqXRH) {
if ( retString === "yes") { // duplicate name
// output message next to input field
$('#username').closest("div").find(".reg_entry_error").html("Name already taken.");
ajax_done_and_successful_flag = false;
} else if ( retString === "no") { // name is okay
// output message next to input field
$('#username').closest("div").find(".reg_entry_error").html("success!");
ajax_done_and_successful_flag = true;
} else {
console.log("in validate_username_duplicate func, success function, string returned was not yes or no." );
$('#username').closest("div").find(".reg_entry_error").html("There are server problems. Try again later.");
ajax_done_and_successful_flag = false;
}
} // end success function
}); // end ajax call
return true; // automatically return true, the true/false is handled in
// the server side program and then the submit handler
}
The reg_entry_error is the place right beside the text input. Here is a simplified code sample of the form.
reg_entry_error是文本输入旁边的位置。下面是表单的简化代码示例。
<label class="reg_entry_label" for="username">Username</label>
<input class="reg_entry_input" type="text" name="username" id="username" value="" />
<span class="reg_entry_error" id="usernameError" ></span>
I hope this answers your question.
我希望这能回答你的问题。
#1
10
http://bugs.jquery.com/ticket/11013#comment:40
http://bugs.jquery.com/ticket/11013评论:40
The use of the Deferred/Promise functionality in synchronous ajax requests has been deprecated in 1.8. The $.ajax method with async: false is supported but you must use a callback parameter rather than a Promise method such as
.then
or.done
.在同步ajax请求中使用Deferred/Promise功能在1.8中已经被弃用。美元的。支持使用async: false的ajax方法,但必须使用回调参数,而不是像.then或.done这样的承诺方法。
So, if you are using the success/complete/error handlers, you can still use async:false
. More info at the jquery ticket above.
因此,如果您正在使用成功/完整/错误处理程序,您仍然可以使用async:false。更多信息请参见上面的jquery代码。
#2
2
As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the complete/success/error callbacks.
对于jQuery 1.8,不赞成在jqXHR ($.Deferred)中使用async: false;您必须使用完整/成功/错误回调。
http://api.jquery.com/jQuery.ajax/ (async section)
http://api.jquery.com/jQuery.ajax/(异步部分)
I found this a bit annoying... developers should be given the choice to make a blocking call with async: false
if its something the platform allows - why restrict it? I'd just set a timeout to minimize the impact of a hang.
我觉得这有点烦人……应该让开发人员选择使用async: false进行阻塞调用,如果平台允许的话——为什么要限制呢?我只需设置一个超时,以最小化挂起的影响。
Nonetheless, I'm using a queue now in 1.8, which is non-blocking, and works quite nicely. Sebastien Roch created a easy to use utility that allows you to queue up functions and run/pause them. https://github.com/mjward/Jquery-Async-queue
尽管如此,我现在使用的队列是1.8,它是非阻塞的,并且工作得很好。Sebastien Roch创建了一个易于使用的实用程序,允许您排队并运行/暂停函数。https://github.com/mjward/Jquery-Async-queue
queue = new $.AsyncQueue();
queue.add(function (queue) { ajaxCall1(queue); });
queue.add(function (queue) { ajaxCall2(queue); });
queue.add(function() { ajaxCall3() });
queue.run();
In the first 2 functions I pass the queue
object into the calls, here's what the calls would look like:
在前两个函数中,我将队列对象传递给调用,如下所示:
function ajaxCall1(queue) {
queue.pause();
$.ajax({
// your parameters ....
complete: function() {
// your completing steps
queue.run();
}
});
}
// similar for ajaxCall2
Notice the queue.pause();
at the beginning of each function, and queue.run()
to continue queue execution at the end of your complete
statement.
注意到queue.pause();在每个函数的开头,和queue.run()在语句结束时继续执行队列。
#3
0
I assume you will be doing full form validation on submit anyway, so perhaps it's no problem if the as-you-type email validation is interrupted, and precedence given to the form submission.
我假设您将在提交时进行完整的表单验证,因此,如果正在输入的电子邮件验证被中断,并优先于表单提交,那么可能没有问题。
I think what I'd do is abort the 'validateEmailRegistered' AJAX request when the user submits the form. Then, perform full server-side form validation as usual - including email validation.
我认为,当用户提交表单时,我将中止“validateemailregister”AJAX请求。然后,像往常一样执行完整的服务器端表单验证——包括电子邮件验证。
My understanding of as-you-type validation is that it's a nicety, not a substitute for validating the form when it is submitted. So it doesn't make sense to me for it to block the form submission.
我对as-you-type验证的理解是,它是一种精确,而不是当它提交时验证表单的替代品。所以阻止表单提交对我来说没有意义。
#4
0
If you are really set on not letting them submit the form until you have checked the email validity, start out your submit button with the disabled
attribute, then have the callback set $('form button').removeAttr('disabled');
如果你真的设置了不让他们提交表单,直到你检查了邮件的有效性,开始你的提交按钮和禁用的属性,然后有回调设置$('表单按钮').removeAttr('禁用');
That being said, I'm with the other people - just let them submit the form! Usually people get it right and you pass them right on through with no errors...
那就是说,我和其他人在一起——让他们提交表格吧!通常情况下,人们做对了,你把他们直接传递过去,没有任何错误……
#5
0
I think you need to change a bit how you it works. Don't try to achieve blocking, but embrace non-blocking.
我认为你需要改变一下你的工作方式。不要试图实现阻塞,而是拥抱非阻塞。
I would do like this: - Keep the validation on email; make it Asynchronous. When it's valid, set a flag somewhere in a variable to know it's ok. - Add a callback on the form.submit() to check whether the email is ok (with the variable) and prevent the submission if it's not.
我想这样做:-保持电子邮件的有效性;要进行异步调用。当它有效时,在变量中某处设置一个标志,以知道它是ok的。-在form.submit()上添加回调,以检查电子邮件(带有变量)是否ok,如果不是,则防止提交。
This way you can keep asynchronous call without freeze the web browser UI.
通过这种方式,您可以保持异步调用,而不必冻结web浏览器UI。
-- [edit] --
——[编辑]
This is some quick code I just wrote for the example based on what you already have.
这是我为这个示例编写的一些快速代码,它基于您已经拥有的内容。
For your information, a programming notion called "promises" (futures and deferred are other terms for it) has been invented to solve exactly the problem you have.
对于你的信息,一个叫做“承诺”的编程概念(期货和递延是它的其他术语)已经被发明来解决你的问题。
Here's an article on what it is and how to use them in JavaScript (using dojo or jQuery): http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx
这里有一篇关于它是什么以及如何在JavaScript(使用dojo或jQuery)中使用它们的文章
<script>
function validateEmailRegistered(input) {
if (input.setCustomValidity === undefined) return;
var err = 'Email address not found';
$.ajax({
url: 'email-is-registered.php',
data: { email: input.value },
success: function(data) {
var ok = data=='true';
input.setCustomValidity(ok ? '' : err);
// If the form was already submited, re-launch the check
if (form_submitted) {
input.form.submit();
}
}
});
}
var form_submitted = false;
function submitForm(form) {
// Save the user clicked on "submit"
form_submitted = true;
return checkForm(form);
}
function checkForm(form, doSubmit) {
if (doSubmit) {
form_submitted = true;
}
// If the email is not valid (it can be delayed due to asynchronous call)
if (!form.email.is_valid) {
return false;
}
return true;
}
</script>
<form method="get" action="nextpage.php" onsumbit="return submitForm(this);">
<input name="email" id="email" type="email" required
onChange="validateEmailRegistered(this)">
<button type="submit">go</button>
<form>
#6
0
You can do it asynchronously.
可以异步完成。
Create a global variable, I call it ajax_done_and_successful_flag, that you initialize to false at the beginning of the program. You will set this to true or false at various places in your Ajax functions such as your Ajax success function or your Ajax error function.
创建一个全局变量,我称之为ajax_done_and_successful_flag,在程序开始时将其初始化为false。您将在Ajax功能(如Ajax成功函数或Ajax错误函数)的不同位置设置为true或false。
Then you need to add a submit handler at the bottom of your validate function.
然后需要在validate函数的底部添加一个submit处理程序。
submitHandler: function(form) {
if (ajax_done_and_successful_flag === true) {
form.submit()
}
}
The problem is the code is not executing in a linear way.
Put a bunch of Firebug's console.log statements in your code.
Observe the sequence of execution. You will see that your
Ajax response will come back last, or whenever it feels like it.
That's why you need the submitHandler AND the global flag
to force the validate function to wait for correct Ajax
results before the form is submitted.
问题是代码不是以线性方式执行的。放一堆Firebug的控制台。代码中的日志语句。观察执行的顺序。您将看到,您的Ajax响应将在最后返回,或者在任何时候返回。这就是为什么需要submitHandler和全局标记来强制validate函数在提交表单之前等待正确的Ajax结果。
Any output to the screen from the Ajax response, needs to be done in the Ajax functions, such as the success function and the error function.
You need to write to the same location as the validate function's success/error functions.
This way the Ajax error messages blend in with the validate function's error function.
This concept may seem a bit tricky.
The idea to keep in mind is that the success and error functions in the validate function are writing to the same location as the success and error functions in the Ajax call, and that is okay, that is how it should be.
The location of my error messages is right next to where the user types the input. This creates a nice user experience that I think you are asking for.
Ajax响应向屏幕输出的任何输出都需要在Ajax函数中完成,比如success函数和error函数。您需要写入与验证函数的成功/错误函数相同的位置。这样,Ajax错误消息与validate函数的错误函数混合在一起。这个概念似乎有点棘手。要记住的是,validate函数中的success和error函数与Ajax调用中的success和error函数写入到相同的位置,这是可以的,这就是应该的。我的错误消息的位置就在用户输入输入的位置旁边。这创造了一个良好的用户体验,我认为你正在要求。
Here is my code sample. I simplified it.
这是我的代码示例。我简化它。
I am running jQuery-1.7.1
and jQuery validation plug-in 1.6
I am using Firefox 14.0.1 and I also tried it on Chrome 21.0 successfully.
我正在运行jQuery-1.7.1和jQuery验证插件1.6,我使用的是Firefox 14.0.1,我还成功地在Chrome 21.0上试用了它。
var ajax_done_and_successful_flag = false;
// Add methods
...
$.validator.addMethod("USERNAME_NOT_DUPLICATE", function (value, element) {
return this.optional(element) || validate_username_not_duplicate( );
},
"Duplicate user name.");
// validate
$(document).ready(function ( ) {
$('#register_entry_form form').validate({
rules: {
username: {
required: true,
minlength: 2,
maxlength: 20,
USERNAME_PATTERN: true,
USERNAME_NOT_DUPLICATE: true
},
...
errorPlacement: function (error, element) {
element.closest("div").find(".reg_entry_error").html(error);
},
success: function(label) {
label.text('Success!');
} ,
submitHandler: function(form) {
if (ajax_done_and_successful_flag === true ) {
form.submit();
}
}
});
});
/* validation functions*/
function validate_username_not_duplicate() {
var username_value = $('#username').val(); // whatever is typed in
$.ajax({
url: "check_duplicate_username.php",
type: "POST",
data: { username: username_value },
dataType: "text",
cache: false,
//async: false,
timeout: 5000,
error: function (jqXHR, errorType, errorMessage) {
ajax_done_and_successful_flag = false;
if ( errorType === "timeout" ) {
$('#username').closest("div").find(".reg_entry_error").html("Server timeout, try again later" );
} else if ...
},
success: function (retString, textStatus,jqXRH) {
if ( retString === "yes") { // duplicate name
// output message next to input field
$('#username').closest("div").find(".reg_entry_error").html("Name already taken.");
ajax_done_and_successful_flag = false;
} else if ( retString === "no") { // name is okay
// output message next to input field
$('#username').closest("div").find(".reg_entry_error").html("success!");
ajax_done_and_successful_flag = true;
} else {
console.log("in validate_username_duplicate func, success function, string returned was not yes or no." );
$('#username').closest("div").find(".reg_entry_error").html("There are server problems. Try again later.");
ajax_done_and_successful_flag = false;
}
} // end success function
}); // end ajax call
return true; // automatically return true, the true/false is handled in
// the server side program and then the submit handler
}
The reg_entry_error is the place right beside the text input. Here is a simplified code sample of the form.
reg_entry_error是文本输入旁边的位置。下面是表单的简化代码示例。
<label class="reg_entry_label" for="username">Username</label>
<input class="reg_entry_input" type="text" name="username" id="username" value="" />
<span class="reg_entry_error" id="usernameError" ></span>
I hope this answers your question.
我希望这能回答你的问题。