it-swarm.com.de

Wie mache ich eine jQuery-Blockierung? AJAX ohne async = false aufrufen?

Ich habe eine Seite, die AJAX eine E-Mail überprüft, bevor ich mit der HTML5-Methode setCustomValidity () fortfahre [mit der Webshims-Bibliothek für ältere Browser].

Damit dies funktioniert, setze ich die async-Option im Aufruf von $ .ajax () auf false, um sie synchron zu machen, und blockiere die Seite, bis die Antwort AJAX eingeht. Andernfalls sendet das Formular, bevor der Ajax-Aufruf zurückkehrt. die Validierung unwirksam zu machen.

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

Ich sehe, dass die asynchrone Option ab jQuery 1.8 veraltet ist.

Wie kann ich diese Blockierungsaktion ohne die asynchrone Option erreichen?

14
ChrisV

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

Die Verwendung der Funktion "Zurückgestellt/Versprechen" in synchronen Ajax-Anforderungen wurde in Version 1.8 als veraltet eingestuft. Die $ .ajax-Methode mit async: false wird unterstützt, Sie müssen jedoch einen Rückrufparameter anstelle einer Promise-Methode wie .then oder .done verwenden.

Wenn Sie also die Handler success/complete/error verwenden, können Sie weiterhin async:false verwenden. Mehr Infos beim jquery ticket oben.

10
Mike

Ab jQuery 1.8 ist die Verwendung von async: false mit jqXHR ($ .Deferred) veraltet. Sie müssen die Rückrufe complete/success/error verwenden.

http://api.jquery.com/jQuery.ajax/ (asynchroner Abschnitt)

Ich fand das etwas ärgerlich ... Entwickler sollten die Wahl haben einen blockierenden Anruf mit async: false zu tätigen, wenn es etwas ist, was die Plattform erlaubt - warum sollte man es einschränken? Ich habe nur eine Zeitüberschreitung festgelegt, um die Auswirkungen eines Hangs zu minimieren.

Trotzdem benutze ich eine Warteschlange in Version 1.8, die nicht blockiert und recht gut funktioniert. Sebastien Roch hat ein benutzerfreundliches Dienstprogramm erstellt, mit dem Sie Funktionen in die Warteschlange stellen und ausführen/anhalten können. 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 den ersten beiden Funktionen übergebe ich das Objekt queue an die Aufrufe. Die Aufrufe sehen folgendermaßen aus:

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

// similar for ajaxCall2

Beachten Sie die queue.pause(); am Anfang jeder Funktion und queue.run(), um die Ausführung der Warteschlange am Ende Ihrer complete-Anweisung fortzusetzen.

2
sonjz

Sie können es asynchron machen.

Erstellen Sie eine globale Variable, ich nenne sie ajax_done_and_successful_flag, die Sie zu Beginn des Programms auf false initialisieren. Sie werden dies an verschiedenen Stellen in Ihren Ajax-Funktionen wie Ihrer Ajax-Erfolgsfunktion oder Ihrer Ajax-Fehlerfunktion auf wahr oder falsch setzen.

Anschließend müssen Sie am Ende Ihrer Validierungsfunktion einen Submit-Handler hinzufügen.

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

Das Problem ist, dass der Code nicht linear ausgeführt wird.
Fügen Sie einige der console.log-Anweisungen von Firebug in Ihren Code ein.
Reihenfolge der Ausführung beachten. Sie werden sehen, dass Ihr
Die Ajax-Antwort wird zuletzt zurückgegeben oder wann immer es sich anfühlt.
Deshalb benötigen Sie den submitHandler UND das globale Flag
, um die Validierungsfunktion zu zwingen, auf korrektes Ajax zu warten
Ergebnisse vor dem Absenden des Formulars.

Jede Ausgabe der Ajax-Antwort auf den Bildschirm muss in den Ajax-Funktionen wie der Erfolgsfunktion und der Fehlerfunktion erfolgen.
Sie müssen an dieselbe Stelle schreiben wie die Erfolgs-/Fehlerfunktionen der Prüffunktion.
Auf diese Weise fügen sich die Ajax-Fehlermeldungen in die Fehlerfunktion der Validierungsfunktion ein.
Dieses Konzept mag etwas knifflig erscheinen.
Beachten Sie, dass die Erfolgs- und Fehlerfunktionen in der Validierungsfunktion an dieselbe Stelle schreiben wie die Erfolgs- und Fehlerfunktionen im Ajax-Aufruf, und das ist in Ordnung, so sollte es auch sein .
Die Position meiner Fehlermeldungen befindet sich direkt neben dem Ort, an dem der Benutzer die Eingabe eingibt. Dies schafft eine nette Benutzererfahrung, die ich denke, dass Sie verlangen.

Hier ist mein Codebeispiel. Ich habe es vereinfacht.

Ich verwende jQuery-1.7.1
und jQuery-Validierungs-Plug-in 1.6
Ich verwende Firefox 14.0.1 und habe es auch in Chrome 21.0 erfolgreich ausprobiert.

 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

}

Der reg_entry_error ist die Stelle direkt neben der Texteingabe. Hier ist ein vereinfachtes Codebeispiel des Formulars.

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

Ich hoffe das beantwortet deine Frage.

0
Ken Johnson

Ich gehe davon aus, dass Sie beim Absenden ohnehin die vollständige Formularüberprüfung durchführen werden. Daher ist es möglicherweise kein Problem, wenn die E-Mail-Überprüfung nach dem Typ Ihrer Person unterbrochen wird und der Formularübermittlung Vorrang eingeräumt wird.

Ich denke, ich würde die Anfrage 'validateEmailRegistered' AJAX abbrechen, wenn der Benutzer das Formular absendet. Führen Sie dann wie gewohnt eine vollständige serverseitige Formularüberprüfung durch - einschließlich der E-Mail-Überprüfung.

Ich verstehe die Überprüfung nach dem Typ des Benutzers so, dass sie ein Vorteil und kein Ersatz für die Überprüfung des Formulars beim Absenden ist. Deshalb macht es für mich keinen Sinn, die Formularübermittlung zu blockieren.

0
Jonathan Nicol

Wenn Sie wirklich möchten, dass sie das Formular erst senden, nachdem Sie die Gültigkeit der E-Mail überprüft haben, beginnen Sie mit der Schaltfläche Senden mit dem Attribut disabled, und lassen Sie den Rückruf auf $('form button').removeAttr('disabled'); setzen.

Davon abgesehen bin ich bei den anderen Leuten - lass sie einfach das Formular einreichen! Normalerweise machen die Leute es richtig und Sie geben sie ohne Fehler weiter ...

0
Ryley

Ich denke, Sie müssen ein bisschen ändern, wie es funktioniert. Versuchen Sie nicht, eine Blockierung zu erreichen, sondern umarmen Sie die Nichtblockierung.

Ich würde das gerne machen: - Bewahre die Bestätigung per E-Mail auf; mach es asynchron. Wenn es gültig ist, setzen Sie irgendwo in einer Variablen ein Flag, um zu wissen, dass es in Ordnung ist. - Fügen Sie einen Rückruf in form.submit () ein, um zu überprüfen, ob die E-Mail (mit der Variablen) in Ordnung ist, und verhindern Sie die Übermittlung, wenn dies nicht der Fall ist.

Auf diese Weise können Sie asynchrone Anrufe führen, ohne die Benutzeroberfläche des Webbrowsers einfrieren zu müssen.

- [bearbeiten] -

Dies ist ein kurzer Code, den ich gerade für das Beispiel geschrieben habe, basierend auf dem, was Sie bereits haben.

Zu Ihrer Information wurde ein Programmierbegriff namens "Versprechen" (Futures und Deferred sind andere Begriffe dafür) erfunden, um genau das Problem zu lösen, das Sie haben.

Hier ist ein Artikel darüber, was es ist und wie man sie in JavaScript verwendet (mit Dojo oder 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
Savageman