2016-08-03 11 views
5

Mam formularz, który w rzeczywistości składa się z dwóch formularzy. Każdy formularz jest formularzem rezerwacji. Istnieją dwa listy rozwijane w obu formach - destination from i destination to. Istnieje równomierny handler, który wywołuje AJAX, aby uzyskać destinations to, gdy miejsce docelowe jest wybierane/zmieniane.Zdarzenie JQuery wyprzedza inny

Kolejny program obsługi zdarzeń (pole wyboru podróży w obie strony) wypełnia listę rozwijaną drugiego formularza, zmieniając miejsca docelowe z pierwszego formularza.

Więc jeśli pierwsza postać posiada:

destination one: France 
destination two: Austria 

Następnie, jeśli jest zaznaczone round trip, druga forma jest natychmiast wypełniona:

destination one: Austria 
destination two: France 

Problemem jest to, że dwa zdarzenia nie współpracują prawidłowo.

Gdy ten kod jest wykonywany:

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(); 

Pierwszy wiersz wywołuje inną procedurę obsługi, która wypełnia drugą formę (jest to jedyny przypadek, gdy nie jest to konieczne). Ponieważ jest to AJAX, druga linia wyprzedza tę AJAX, więc teraz druga forma jest poprawnie wypełniona (zmienione miejsca docelowe z pierwszego formularza), ale po zakończeniu AJAX zmienia wybór pola destination two.

Czy istnieje sposób, aby tego uniknąć? Na przykład, aby wyłączyć procedurę obsługi zdarzeń lub lepiej wykonać tę czynność, aż zostanie wykonana AJAX, a następnie będzie kontynuowana. Nie mogę po prostu zrobić .off() na polu destination to, ponieważ używam wtyczki select2.

Oto mój 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

można utworzyć https://jsfiddle.net lub dodać kod HTML –

Odpowiedz

2

jeśli jestem zrozumienie poprawnie, masz problem współbieżności. Zasadniczo chcesz, aby twoje pierwsze wywołanie ajaxowe zostało przerwane przed wywołaniem drugiego prawa?

Nie widzę żadnych żądań ajax w twoim kodzie, ale myślę, że paramter asynchroniczny: false, może być tym, czego potrzebujesz.

Sprawdź dokumentację: http://api.jquery.com/jquery.ajax/

Nadzieja pomaga

+0

Witam, dzięki za odpowiedź, dodałem resztę w skrypcie koniec pytania. Tak naprawdę pomógł async, ale nie jest to najlepszy pomysł, ponieważ jest potrzebny tylko wtedy, gdy zaznaczone jest pole wyboru podróży w obie strony. –

+0

Ideałem byłoby coś w stylu id_form_1_destination_from.val (destination_to_0.val()). Change(). MakeAjaxAsyncForThisTime() .... –

+0

* makeAjaxSyncForThisTime() ... –

1

pewno mają klasyczny wyścig „stan” tu dzieje.

Ponieważ połączenia AJAX wydają się dość niezwiązane ze sobą, może być konieczne dodanie kodu po stronie JavaScript, aby potencjalnie "wyścigowe" sytuacje nie mogły wystąpić. Na przykład, aby rozpoznać, że combo "jest wypełniane", jeśli wydałeś żądanie AJAX, aby je wypełnić, ale jeszcze nie otrzymałeś odpowiedzi. Możesz wyłączyć niektóre przyciski.

Nawiasem mówiąc, w sytuacjach takich jak ten, gdzie są dwa formularze (lub więcej ...) lubię próbować scentralizować logikę. Na przykład może istnieć "obiekt singletonowy", którego zadaniem jest poznanie obecnego stanu wszystkiego, co dzieje się na hoście lub z nim. Maszyna skończonego stanu (FSM) (bełkot, mumble ...) działa tutaj bardzo dobrze. Ten obiekt może rozgłaszać zdarzenia, aby poinformować "słuchaczy", kiedy muszą zmienić swoje przyciski i tym podobne.

+0

Javascript nie ma warunków wyścigu, ponieważ jest jednowątkowy. W tym przypadku problem polega na tym, że XHR od pierwszego kliknięcia nie jest zatrzymywany po uruchomieniu drugiego. Dlatego oba są kompletne, a ich kolejność nie może zostać zagwarantowana. Nie jest to jednak sytuacja wyścigowa, ponieważ żadna z nich nie przeszkadza sobie nawzajem. –

0

Musisz anulować pierwsze żądanie AJAX przed rozpoczęciem drugiego. Z tego SO pytanie:

Abort Ajax requests using jQuery

var xhr; 

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