2012-06-16 47 views
13

Tôi có trang xác thực AJAX email trước khi tiếp tục sang trang tiếp theo, sử dụng phương thức setCustomValidity() HTML5 [sử dụng thư viện webshims cho các trình duyệt cũ hơn]. Để làm việc này, tôi đặt tùy chọn async thành false trong lệnh $ .ajax() để làm cho nó đồng bộ, chặn trang đang chờ phản hồi AJAX, nếu không, biểu mẫu sẽ gửi trước khi cuộc gọi ajax trả về, hiển thị xác nhận không hiệu quả.Làm cách nào để thực hiện cuộc gọi AJAX chặn jQuery mà không có async = false?

<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> 

Tôi thấy tùy chọn không đồng bộ sẽ không còn được dùng như jQuery 1.8 nữa.

Làm cách nào để có thể đạt được hành động chặn này mà không có tùy chọn không đồng bộ?

+0

Bạn đã sử dụng giải pháp nào? Tôi đang đối mặt với cùng một vấn đề. –

Trả lời

0

Tôi cho rằng bạn sẽ thực hiện xác thực biểu mẫu đầy đủ khi gửi, vì vậy có lẽ không có vấn đề gì nếu xác thực email như bạn bị gián đoạn và ưu tiên cho việc gửi biểu mẫu.

Tôi nghĩ điều tôi muốn làm là hủy bỏ yêu cầu AJAX 'validateEmailRegistered' khi người dùng gửi biểu mẫu. Sau đó, thực hiện xác thực biểu mẫu phía máy chủ đầy đủ như thường lệ - bao gồm xác thực email.

Sự hiểu biết của tôi về xác thực theo loại bạn là tính xác thực, không phải thay thế để xác thực biểu mẫu khi được gửi. Vì vậy, nó không có ý nghĩa với tôi cho nó để ngăn chặn việc gửi biểu mẫu.

+0

Tôi cũng đang thực hiện xác thực phía máy chủ nhưng cung cấp tương tác người dùng kém hơn so với cuộc gọi AJAX chặn cung cấp phản hồi của người dùng thông qua cơ chế (setCustomValidity) thông thường. Xác thực phía máy khách không thay thế cho xác thực phía máy chủ, nhưng cung cấp trải nghiệm người dùng tốt hơn. Một thông báo lỗi phía máy chủ chỉ là một cách chặn khác, thực sự ... – ChrisV

0

Tôi nghĩ bạn cần thay đổi một chút về cách hoạt động của nó. Đừng cố gắng để đạt được chặn, nhưng nắm lấy không bị chặn.

Tôi sẽ làm như sau: - Giữ xác thực qua email; làm cho nó không đồng bộ. Khi nó hợp lệ, hãy đặt cờ ở đâu đó trong một biến để biết nó là ok. - Thêm một cuộc gọi lại trên form.submit() để kiểm tra xem email có ổn không (với biến) và ngăn chặn việc gửi nếu không.

Bằng cách này bạn có thể giữ cuộc gọi không đồng bộ mà không đóng băng giao diện người dùng trình duyệt web.

- [chỉnh sửa] -

Đây là mã nhanh mà tôi vừa viết cho ví dụ dựa trên những gì bạn đã có.

Để biết thông tin của bạn, khái niệm lập trình được gọi là "lời hứa" (tương lai và trì hoãn là các điều khoản khác cho nó) đã được phát minh để giải quyết chính xác vấn đề bạn có.

Dưới đây là một bài viết về những gì nó là gì và làm thế nào để sử dụng chúng trong Javascript (sử dụng võ đường hoặc 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

Sử dụng gọi lại trên biểu mẫu gửi để ngăn chặn gửi là chính xác những gì tôi muốn đạt được, nhưng tôi không thấy làm thế nào tôi có thể làm điều đó nếu gọi lại là không đồng bộ ... – ChrisV

0

Nếu bạn đang thực sự đặt trên không cho họ gửi biểu mẫu cho đến khi bạn đã kiểm tra hiệu lực của email, hãy bắt đầu nút gửi của bạn với thuộc tính disabled, sau đó có bộ gọi lại $('form button').removeAttr('disabled');

Điều đó đang được nói, tôi là người khác - chỉ cần cho phép họ gửi biểu mẫu! Thông thường mọi người hiểu đúng và bạn vượt qua chúng ngay lập tức mà không có lỗi ...

0

Bạn có thể làm điều đó một cách không đồng bộ.

Tạo biến toàn cầu, tôi gọi nó là ajax_done_and_successful_flag, mà bạn khởi tạo sai ở đầu chương trình . Bạn sẽ đặt giá trị này thành true hoặc false tại các địa điểm khác nhau trong các hàm Ajax của bạn, chẳng hạn như thành công Ajax của bạn hoặc chức năng lỗi Ajax của bạn.

Sau đó, bạn cần thêm trình xử lý gửi ở cuối chức năng xác thực của bạn.

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

Vấn đề là mã không thực thi theo cách tuyến tính.
Đặt một loạt các câu lệnh console.log của Firebug trong mã của bạn.
Quan sát chuỗi thực thi. Bạn sẽ thấy rằng phản hồi của bạn
Ajax sẽ trở lại sau cùng hoặc bất cứ khi nào nó cảm thấy như vậy.
Đó là lý do tại sao bạn cần trình xử lý VÀ cờ toàn cầu
để buộc chức năng xác thực phải đợi cho đúng kết quả Ajax
trước khi gửi biểu mẫu.

Mọi đầu ra cho màn hình từ phản hồi Ajax, cần được thực hiện trong các chức năng Ajax , chẳng hạn như chức năng thành công và chức năng lỗi .
Bạn cần phải viết thư đến cùng một vị trí làm chức năng lỗi/thành công của hàm xác thực.
Bằng cách này, các thông báo lỗi Ajax hòa trộn với hàm lỗi của hàm xác thực.
Khái niệm này có vẻ hơi phức tạp.
Ý tưởng giữ trong ý tưởng là các hàm thành công và lỗi trong hàm xác thực được ghi đến cùng một vị trí thành công và lỗi các chức năng trong cuộc gọi Ajax, và đó là không sao, đó là cách được.
Vị trí của thông báo lỗi của tôi nằm ngay bên cạnh nơi người dùng nhập . Điều này tạo ra trải nghiệm người dùng tốt đẹp mà tôi nghĩ rằng bạn đang yêu cầu.

Đây là mẫu mã của tôi. Tôi đã đơn giản hóa nó.

Tôi đang chạy jQuery-1.7.1
và jQuery xác nhận plug-in 1,6
Tôi đang sử dụng Firefox 14.0.1 và tôi cũng đã cố gắng nó trên Chrome 21.0 thành công.

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 là vị trí ngay bên cạnh đầu vào văn bản. Đây là mẫu mã đơn giản của biểu mẫu.

<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> 

Tôi hy vọng điều này sẽ trả lời câu hỏi của bạn.

1

Kể từ jQuery 1.8, việc sử dụng async: false với jqXHR ($ .Deferred) là không được dùng nữa; bạn phải sử dụng gọi lại hoàn tất/thành công/lỗi.

http://api.jquery.com/jQuery.ajax/ (async phần)

Tôi thấy điều này một chút khó chịu ... các nhà phát triển cần được lựa chọn để thực hiện cuộc gọi chặn với async: false nếu một cái gì đó của mình nền tảng cho phép - tại sao hạn chế nó? Tôi chỉ cần thiết lập một thời gian chờ để giảm thiểu tác động của hang.

Tuy nhiên, hiện tại tôi đang sử dụng hàng đợi là 1,8, không bị chặn và hoạt động khá độc đáo. Sebastien Roch đã tạo ra một tiện ích dễ sử dụng cho phép bạn xếp hàng các chức năng và chạy/tạm dừng chúng. 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(); 

Trong 2 chức năng đầu tiên tôi vượt qua các đối tượng queue vào cuộc gọi, đây là những gì các cuộc gọi sẽ trông như thế:

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

// similar for ajaxCall2 

Thông báo các queue.pause(); vào đầu mỗi chức năng, và queue.run() để tiếp tục thực hiện hàng đợi vào cuối câu lệnh complete của bạn.

+0

Điều này có vẻ đẹp nhưng liên kết đã chết: ( – Gus

+1

cảm ơn cho người đứng đầu lên @ Gus, tôi googled và tìm thấy dự án chuyển đến một tài khoản github khác nhau. – sonjz

10

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

Việc sử dụng các chức năng Hoãn/Promise trong các yêu cầu ajax đồng bộ đã bị phản đối 1.8. Phương thức $ .ajax có async: false được hỗ trợ nhưng bạn phải sử dụng tham số gọi lại thay vì phương thức Promise chẳng hạn như .then hoặc .done.

Vì vậy, nếu bạn đang sử dụng trình xử lý thành công/hoàn thành/lỗi, bạn vẫn có thể sử dụng async:false. Thông tin thêm tại vé jquery ở trên.

Các vấn đề liên quan