2012-06-16 9 views
13

Ho una pagina che esegue la convalida AJAX di una e-mail prima di passare alla pagina successiva, utilizzando il metodo HTML5 setCustomValidity() [utilizzando la libreria webshims per i browser meno recenti].Come posso fare un jQuery bloccando la chiamata AJAX senza async = false?

per questo lavoro, ho impostato l'opzione async su false nella $ .ajax() chiamata per renderlo sincrono, bloccando la pagina in attesa della risposta AJAX, altrimenti il ​​modulo invia prima i ajax chiamata restituisce, rendendo la validazione inefficace.

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

Vedo che l'opzione async deve essere deprecata come di jQuery 1.8.

Come posso ottenere questa azione di blocco senza l'opzione asincrona?

+0

Quale soluzione hai utilizzato? Sto affrontando lo stesso problema. –

risposta

0

Suppongo che eseguirai la convalida del modulo completo in qualsiasi momento, quindi forse non è un problema se la convalida della posta elettronica di tipo you-you viene interrotta e la precedenza viene data all'invio del modulo.

Penso che quello che farei sia interrompere la richiesta AJAX "validateEmailRegistered" quando l'utente invia il modulo. Quindi, eseguire normalmente la convalida completa del modulo sul lato server, inclusa la convalida dell'email.

La mia comprensione della convalida di tipo utente è che è un valore, non un sostituto per la convalida del modulo quando viene inviato. Quindi non ha senso per me bloccare l'invio del modulo.

+0

Sto eseguendo anche la convalida sul lato server, ma ciò fornisce un'interazione utente peggiore rispetto a una chiamata AJAX di blocco che ha fornito il feedback dell'utente attraverso il meccanismo regolare (setCustomValidity). La convalida lato client non sostituisce la convalida lato server, ma offre un'esperienza utente migliore. Un messaggio di errore sul lato server è solo un altro modo di bloccare, davvero ... – ChrisV

0

Penso che sia necessario cambiare un po 'come funziona. Non cercare di ottenere il blocco, ma abbracciare il non-blocco.

Farei così: - Mantenere la convalida via e-mail; renderlo asincrono. Quando è valido, imposta un flag da qualche parte in una variabile per sapere che è ok. - Aggiungi una richiamata sul form.submit() per verificare se l'e-mail è ok (con la variabile) e impedire l'invio se non lo è.

In questo modo è possibile mantenere la chiamata asincrona senza bloccare l'interfaccia utente del browser.

- [modifica] -

Questo è qualche rapido codice che ho appena scritto per l'esempio in base a ciò che già avete.

Per vostra informazione, una nozione di programmazione chiamata "promesse" (futures e differiti sono altri termini) è stata inventata per risolvere esattamente il problema che avete.

Ecco un articolo su che cosa è e come usarli in JavaScript (utilizzando dojo o 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

Usare una richiamata sul modulo per prevenire l'invio è esattamente quello che voglio ottenere, ma non vedo come posso farlo se la richiamata è asincrono ... – ChrisV

0

Se siete veramente impostato su non permettendo loro di inviare il modulo prima di aver controllato il validità della posta elettronica, avviare il pulsante di invio con l'attributo disabled, quindi impostare la callback $('form button').removeAttr('disabled');

Detto questo, sono con le altre persone - lascia che inviino il modulo! Di solito le persone lo fanno bene e li passi avanti senza errori ...

0

Puoi farlo in modo asincrono.

Creare una variabile globale, io lo chiamo ajax_done_and_successful_flag, da inizializzare a false all'inizio del programma . Imposterai questa opzione su true o false in vari posti nelle tue funzioni Ajax come la tua funzione Ajax successo o la tua funzione di errore Ajax.

Quindi è necessario aggiungere un gestore di invio nella parte inferiore della funzione di convalida di .

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

Il problema è che il codice non è in esecuzione in modo lineare.
Inserisci un po 'di istruzioni console.log di Firebug nel codice.
Osservare la sequenza di esecuzione. Vedrai che la tua risposta Ajax Ajax tornerà per ultima, o ogni volta che lo desideri.
Ecco perché è necessario il submitHandler e la bandiera globale
per forzare la funzione di convalida di aspettare per una corretta Ajax
risultati prima che il modulo viene inviato.

Qualsiasi uscita allo schermo dalla risposta Ajax, deve essere fatto nei funzioni Ajax, come la funzione successo e la funzione errore.
È necessario scrivere nella stessa posizione come funzioni di successo/errore della funzione di convalida.
In questo modo i messaggi di errore Ajax si fondono con la funzione di errore della funzione di convalida.
Questo concetto può sembrare un po 'complicato.
L'idea di tenere a mente è che le funzioni di successo e di errore nella funzione validate stanno scrivendo nella stessa posizione come il successo e l'errore funzioni nella chiamata Ajax, e che va bene, che è come dovrebbe essere.
L'ubicazione dei miei messaggi di errore è proprio accanto a dove l'utente digita l'input. Questo crea una bella esperienza utente che penso tu stia chiedendo.

Ecco il mio esempio di codice. L'ho semplificato.

Sono in esecuzione jQuery 1.7.1-
e jQuery convalida plug-in 1.6
sto usando Firefox 14.0.1 e ho anche provato su Chrome 21,0 successo.

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 

} 

Il reg_entry_error è il luogo proprio accanto il metodo di scrittura. Ecco un esempio di codice semplificato del modulo.

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

Spero che questo risponda alla tua domanda.

1

Come di jQuery 1.8, l'uso di async: false con jqXHR ($ .Deferred) è deprecato; è necessario utilizzare i callback completi/di successo/errore.

http://api.jquery.com/jQuery.ajax/ (sezione asincrona)

ho trovato questo un po 'fastidioso ... gli sviluppatori dovrebbero essere data la scelta per effettuare una chiamata di blocco con async: false se qualcosa la piattaforma consente - il motivo per limitarla? Avrei appena impostato un timeout per ridurre al minimo l'impatto di un blocco.

Tuttavia, sto usando una coda ora in 1.8, che non è bloccante, e funziona molto bene. Sebastien Roch ha creato un'utilità facile da usare che ti permette di mettere in coda le funzioni ed eseguirle/metterle in pausa. 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(); 

Nei primi 2 funzioni che passare l'oggetto queue nelle chiamate, ecco cosa le chiamate sarebbe simile:

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

// similar for ajaxCall2 

Avviso del queue.pause(); all'inizio di ogni funzione, e queue.run() per continuare l'esecuzione della coda alla fine della tua istruzione complete.

+0

Questo sembra bello ma il collegamento è morto :( – Gus

+1

grazie per l'heads up @Gus, ho cercato su Google e ho trovato il progetto spostato su un altro account github. – sonjz

10

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

L'utilizzo della funzionalità/Promessa differite nelle richieste Ajax sincrona è stata deprecata nella 1.8. Il metodo $ .ajax con async: false è supportato ma è necessario utilizzare un parametro di callback anziché un metodo Promise come .then o .done.

Quindi, se si utilizzano i gestori di successo/completamento/errore, è comunque possibile utilizzare async:false. Maggiori informazioni sul biglietto jquery sopra.

Problemi correlati