2012-06-16 46 views
13

使用HTML5 setCustomValidity()方法[使用舊版瀏覽器的webshims庫],我有一個頁面在繼續進行下一頁之前對電子郵件進行AJAX驗證。如何在不使用async = false的情況下阻止AJAX調用?

爲此,我在$ .ajax()調用中將異步選項設置爲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> 

我看到async選項不推薦使用jQuery 1.8。

如何在沒有異步選項的情況下實現此阻止操作?

+0

你最終使用了什麼解決方案?我面臨同樣的問題。 –

回答

0

我假設您將在提交時進行完整的表單驗證,因此如果您的類型電子郵件驗證被中斷,並且表單提交的優先級可能沒有問題。

我想我會做,當用戶提交表單被中止「validateEmailRegistered」 AJAX請求是什麼。然後,照常執行完整的服務器端表單驗證 - 包括電子郵件驗證。

我對as-you-type驗證的理解是,它是一個很好的,而不是提交時驗證表單的替代方法。所以它阻止表單提交對我來說沒有任何意義。

+0

我也在做服務器端驗證,但是它提供的用戶交互不如通過常規(setCustomValidity)機制提供用戶反饋的阻塞AJAX調用。客戶端驗證不能替代服務器端驗證,但可提供更好的用戶體驗。服務器端的錯誤信息只是阻塞的另一種方式,真的... – ChrisV

0

我認爲你需要改變一下它是如何工作的。不要試圖實現阻塞,但要擁抱非阻塞。

我會做這樣的: - 請確認電子郵件上;使其成爲異步。當它有效時,在變量的某個地方設置一個標誌,以確定它是否正確。 - 在form.submit()上添加回調以檢查電子郵件是否正確(使用變量),如果不是,則阻止提交。

這種方式可以保持異步調用而不會凍結Web瀏覽器UI。

- [編輯] -

這是一些簡單的代碼我只是寫了基於你已經擁有的例子。

爲了您的信息,一個名爲「承諾」(期貨和延期是其他條款)的編程概念已經發明,以解決您的問題。

下面是關於它是什麼,以及如何在JavaScript中使用它們(使用道場或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> 
+0

在表單提交時使用回調來阻止提交正是我想要實現的,但我不明白如何在回調時如何執行回調是異步的... – ChrisV

0

如果你是真正建立在不讓他們提交表單,直到檢查完電子郵件的有效性,開始了你與disabled屬性提交按鈕,則有回調設置$('form button').removeAttr('disabled');

話雖這麼說,我與其他人 - 只是讓他們提交表單!通常情況下,人們可以正確地通過它們,並且無錯地通過它們...

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語句。
觀察執行的順序。你會看到你的最後回來,或者只要感覺就像它一樣。
這就是爲什麼您需要submitHandler和全局標誌
來強制validate函數在提交表單之前等待正確的Ajax
結果。

的任何輸出從Ajax響應屏幕時, 需要在 Ajax函數來完成,如成功函數和 誤差函數。
您需要寫入相同的位置 作爲驗證函數的成功/錯誤函數。
這樣,Ajax錯誤消息與驗證函數的 錯誤函數混合在一起。
這個概念可能看起來有點棘手。
的想法保持 一點是,在驗證功能 的成功和錯誤功能寫入同一位置,如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> 

我希望這能回答你的問題。

1

從jQuery 1.8開始,使用異步:false與jqXHR($ .Deferred)是 棄用;您必須使用完整/成功/錯誤回調。

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聲明末尾繼續排隊執行。

+0

這看起來不錯,但鏈接已經死了:( – Gus

+1

感謝@Gus,我GOOGLE了,發現項目移動到不同的github帳戶。 – sonjz

10

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

採用同步Ajax請求的遞延/無極功能已被棄用1.8。支持async:false的$ .ajax方法,但您必須使用回調參數而不是Promise方法,如.then.done

因此,如果您使用的是成功/完整/錯誤處理程序,仍然可以使用async:false。更多信息在上面的jquery門票。

相關問題