14

我有一个页面使用 HTML5 setCustomValidity() 方法[使用旧浏览器的 webshims 库],在继续到下一页之前对电子邮件进行 AJAX 验证。

为此,我在 $.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>

我看到从 jQuery 1.8 开始不推荐使用 async 选项。

如果没有 async 选项,如何实现此阻止操作?

4

6 回答 6

10

http://bugs.jquery.com/ticket/11013#comment:40

在同步 ajax 请求中使用 Deferred/Promise 功能已在 1.8 中弃用。支持带有 async: false 的 $.ajax 方法,但您必须使用回调参数而不是 Promise 方法,例如.thenor .done

因此,如果您使用的是成功/完成/错误处理程序,您仍然可以使用async:false. 更多信息在上面的 jquery 票上。

于 2012-10-26T18:13:20.547 回答
2

从 jQuery 1.8 开始,不推荐在 jqXHR ($.Deferred) 中使用 async: false ;您必须使用完成/成功/错误回调。

http://api.jquery.com/jQuery.ajax/(异步部分)

我发现这有点烦人......如果平台允许,开发人员应该可以选择进行阻塞调用async: false- 为什么要限制它?我只是设置了一个超时以最大程度地减少挂起的影响。

尽管如此,我现在在 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();

在前 2 个函数中,我将queue对象传递给调用,调用如下所示:

function ajaxCall1(queue) {
    queue.pause();
    $.ajax({
       // your parameters ....
       complete: function() {
         // your completing steps
         queue.run();
       }
    });
}

// similar for ajaxCall2

注意queue.pause();每个函数开头的 ,并在语句queue.run()末尾继续队列执行。complete

于 2012-10-25T14:43:21.710 回答
0

我假设您无论如何都会在提交时进行完整的表单验证,所以如果您键入电子邮件验证被中断,并且优先考虑表单提交,也许没问题。

我想我要做的是在用户提交表单时中止“validateEmailRegistered”AJAX 请求。然后,像往常一样执行完整的服务器端表单验证——包括电子邮件验证。

我对 as-you-type 验证的理解是,它是一种很好的方式,而不是在提交表单时验证表单的替代品。所以阻止表单提交对我来说没有意义。

于 2012-06-16T11:24:57.370 回答
0

您可以异步执行此操作。

创建一个全局变量,我称之为 ajax_done_and_successful_flag,您在程序开始时将其初始化为 false。您将在 Ajax 函数(例如 Ajax 成功函数或 Ajax 错误函数)的各个位置将其设置为 true 或 false。

然后您需要在验证函数的底部添加一个提交处理程序。

submitHandler: function(form) {
   if (ajax_done_and_successful_flag === true) {
     form.submit()
   }
}  

问题是代码没有以线性方式执行。
在您的代码中放置一堆 Firebug 的 console.log 语句。
观察执行顺序。您将看到您的
Ajax 响应将最后返回,或者任何时候都返回。
这就是为什么您需要 submitHandler 和全局标志来强制验证函数 在提交表单之前
等待正确的 Ajax结果。

任何从 Ajax 响应到屏幕的输出,都需要在 Ajax 函数中完成,例如成功函数和错误函数。
您需要写入与验证函数的成功/错误函数相同的位置。
通过这种方式,Ajax 错误消息与 validate 函数的错误函数融合在一起。
这个概念可能看起来有点棘手。
要记住的想法是,验证函数中的成功和错误函数与 Ajax 调用中的成功和错误函数写入相同的位置,这没关系,应该是这样。
我的错误消息的位置就在用户键入输入的位置旁边。这创造了我认为您所要求的良好用户体验。

这是我的代码示例。我简化了它。

我正在运行 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

}

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>  

我希望这回答了你的问题。

于 2012-08-31T17:47:52.160 回答
0

我认为你需要改变一下你的工作方式。不要试图实现阻塞,而要拥抱非阻塞。

我会这样做: - 保留电子邮件验证;使其异步。当它有效时,在变量中的某处设置一个标志以知道它是好的。- 在 form.submit() 上添加回调以检查电子邮件是否正常(使用变量),如果不正常则阻止提交。

这样您就可以保持异步调用而不会冻结 Web 浏览器 UI。

- [编辑] -

这是我刚刚根据您已有的内容为示例编写的一些快速代码。

供您参考,已经发明了一种称为“承诺”(期货和延期是它的其他术语)的编程概念,以准确解决您遇到的问题。

这是一篇关于它是什么以及如何在 JavaScript 中使用它们(使用 dojo 或 jQuery)的文章:http: //blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript -with-promises.aspx

<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>
于 2012-06-16T11:29:42.093 回答
0

如果您真的决定在检查电子邮件有效性之前不让他们提交表单,请使用disabled属性启动提交按钮,然后设置回调$('form button').removeAttr('disabled');

话虽如此,我和其他人在一起 - 让他们提交表格!通常人们做对了,你把它们传递出去,没有错误……

于 2012-06-18T15:30:51.073 回答