2016-08-03 3 views
5

übernommen Ich habe ein Formular, das tatsächlich aus zwei Formen besteht. Jedes Formular ist ein Reservierungsformular. Es gibt zwei Dropdown-Listen in beiden Formen - destination from und destination to. Es gibt einen geraden Handler, der AJAX anruft, um destinations to zu erhalten, wenn das Ziel von ausgewählt/geändert wird.JQuery Ereignis wird von einem anderen

Ein anderer Event-Handler (Round-Trip-Checkbox) füllt die Dropdown-Listen für das zweite Formular, indem die Ziele vom ersten Formular aus gewechselt werden.

Also, wenn die erste Form hat:

destination one: France 
destination two: Austria 

Wenn dann round trip aktiviert ist, wird die zweite Form sofort gefüllt:

destination one: Austria 
destination two: France 

Das Problem ist, dass diese beiden Ereignisse nicht kooperieren korrekt.

Wenn dieser Code ausgeführt wird:

id_form_1_destination_from.val(destination_to_0.val()); 
id_form_1_destination_to.val(destination_from_0.val()); 
id_form_1_destination_from.change(); 
id_form_1_destination_to.change(); 

Die erste Zeile ruft eine andere Prozedur, die (das ist der einzige Fall, wenn es nicht benötigt wird) eine zweite Form füllt. Da es AJAX ist, überholt die zweite Zeile diese AJAX, so jetzt ist das zweite Formular korrekt ausgefüllt (Ziele aus dem ersten Formular umgeschaltet), aber wenn AJAX fertig ist, ändert es die Auswahl des destination two Felds.

Gibt es eine Möglichkeit, dies zu vermeiden? Um zum Beispiel den Event-Handler abzuschalten oder besser JQuery warten zu lassen, bis die AJAX fertig ist und dann weiter geht. Ich kann nicht einfach .off() auf destination to Feld, weil ich select2 Plugin verwenden.

Hier ist meine JQuery:

$(document).ready(function() { 
    var destination_from_0 = $("#id_form-0-destination_from"); 
    var destination_to_0 = $('#id_form-0-destination_to'); 
    var ride_two = $('#ride_two'); 

    $('.class-destination-from').on('change', function() { 
     destination_from_changed.call(this); 
    }); 

    $("#id_round_trip").on('change', function() { 

     if (($('#id_round_trip').is(':checked'))) { 

      var id_form_1_destination_from =$('#id_form-1-destination_from'); 
      var id_form_1_destination_to = $('#id_form-1-destination_to'); 

      ride_two.show('fast'); 

      //id_form_1_destination_from.off(); 
      id_form_1_destination_from.val(destination_to_0.val()).change(); 
      //id_form_1_destination_from.on(); 
      //id_form_1_destination_from.change(); 
      id_form_1_destination_to.val(destination_from_0.val()).change(); 


     }else{ 
      ride_two.hide('fast'); 
      ride_two.find(':input').not(':button, :submit, :reset, :checkbox, :radio').val('').change(); 
      ride_two.find(':checkbox, :radio').prop('checked', false).change(); 
     } 
    }); 
    $('.class-destination-to').on('change', destination_to_changed); 



}); 

function destination_to_changed() { 
    var destination_id = $(this).val(); 
    var arrival_container = $(this).siblings('.arrival-container'); 
    var departure_container = $(this).siblings('.departure-container'); 

    if (destination_id == '') { 
     return; 
    } 
    $.ajax({ 
     url: '/ajax/is-airport/' + destination_id + '/', 
     success: function (data) { 
      if (data.status == true) { 
       arrival_container.hide("slow"); 
       departure_container.show("slow"); 

      } 
      if (data.status == false) { 

       departure_container.hide("slow"); 
       arrival_container.show("slow"); 
      } 
      arrival_container.change(); 
      departure_container.change(); 
     } 
    }) 
} 

function destination_from_changed() { 
    var destination_id = $(this).val(); 
    if (destination_id == '') { 
     return; 
    } 
    var ajax_loading_image = $('#ajax-loading-image'); 
    var destination_to = $(this).siblings('.class-destination-to'); 
    destination_to.empty(); 
    ajax_loading_image.show(); 
    $.ajax({ 
     url: '/ajax/get-destination-to-options/' + destination_id + '/', 
     async:false, // ADDED NOW - THIS HELPED BUT IT'S NOT NECESSARY EVERYTIME 
     success: function (data) { 
      ajax_loading_image.hide(); 
      destination_to.append('<option value="" selected="selected">' + "---------" + '</option>'); 
      $.each(data, function (key, value) { 
       destination_to.append('<option value="' + key + '">' + value + '</option>'); 
      }); 
      destination_to.change(); 
     } 
    }) 
} 
+1

können Sie einen https://jsfiddle.net erstellen oder einen HTML-Code –

Antwort

2

Wenn ich mich richtig verstehen, können Sie eine Gleichzeitigkeit Problem haben. Sie möchten grundsätzlich, dass Ihr erster Ajax-Anruf beendet wird, bevor Sie das zweite Recht anrufen?

Ich sehe keine Ajax-Anfrage in Ihrem Code, aber ich denke, der Parameter async: false, könnte was Sie brauchen.

Überprüfen Sie die Dokumentation: http://api.jquery.com/jquery.ajax/

Hoffe, dass es

+0

Hallo, danke für die Antwort hinzufügen, habe ich den Rest des Skripts hinzugefügt bei der Grund der Frage. In der Tat half async, aber es ist keine beste Idee, da es nur benötigt wird, wenn das Kontrollkästchen "Rundum-Trip" aktiviert ist. –

+0

Das Ideal wäre etwas wie id_form_1_destination_from.val (destination_to_0.val()). Change(). MakeAjaxAsyncForThisTime() .... –

+0

* makeAjaxSyncForThisTime() ... –

1

hilft Sie haben definitiv ein klassisches "Race Condition" hier geht.

Da die AJAX-Aufrufe relativ unzusammenhängend zu sein scheinen, müssen Sie möglicherweise etwas Code auf der JavaScript-Seite hinzufügen, damit keine "Rennsituationen" auftreten können. Zum Beispiel, um zu erkennen, dass eine Combo "bevölkert" ist, wenn Sie eine AJAX-Anfrage zum Auffüllen gestellt haben, aber die Antwort noch nicht erhalten haben. Sie können bestimmte Schaltflächen deaktivieren.

Übrigens, in Situationen wie dieser, wo zwei (oder mehr ...) Formen beteiligt sind, möchte ich versuchen, die Logik zu zentralisieren. Zum Beispiel könnte es "ein Singleton-Objekt" geben, dessen Aufgabe es ist, den gegenwärtigen Status von allem, was auf oder mit dem Host ausgeführt wird, zu kennen. Ein endlicher Automat (FSM) (murmeln, murmeln ...) funktioniert hier sehr gut. Dieses Objekt kann Ereignisse senden, um "Listener" zu informieren, wenn sie ihre Schaltflächen usw. ändern müssen.

+0

Javascript hat keine Race-Bedingungen, weil es Singlethread ist. In diesem Fall besteht das Problem darin, dass das XHR beim ersten Klick nicht gestoppt wird, wenn das zweite gestartet wird. Daher sind beide abgeschlossen und die Reihenfolge, in der sie abgeschlossen sind, kann nicht garantiert werden. Dies ist jedoch keine Race Condition, da sich keine der beiden Anfragen gegenseitig stört. –

0

Sie müssen die erste AJAX-Anfrage abbrechen, bevor Sie die zweite starten. Aus dieser Frage SO:

Abort Ajax requests using jQuery

var xhr; 

function getData() { 
    if (xhr) { xhr.abort(); } 
    xhr = $.ajax(...); 
} 
Verwandte Themen