jquery - w przypadku sukcesu zwracana wartość przy użyciu wyniku AJAX

96

Mam mały problem z funkcją jquery $ .ajax ().

Mam formularz, w którym każde kliknięcie przycisku opcji lub wybór z menu rozwijanego tworzy zmienną sesji z wybraną wartością.

Teraz - mam jedno z menu rozwijanych, które ma 4 opcje - pierwsza z nich (z etykietą Brak) ma wartość = "", pozostałe mają swoje identyfikatory.

To, co chcę, to opcja Brak (z pustą wartością), aby usunąć sesję i inna, aby ją utworzyć, ale tylko wtedy, gdy sesja o tej konkretnej nazwie wyboru jeszcze nie istnieje - ponieważ wszystkie inne opcje mają przypisaną tę samą ilość - wskazuje tylko, który z nich został wybrany.

Nie jestem pewien, czy to ma sens - ale spójrz na kod - być może to wyjaśni to:

$("#add_ons select").change(function() {
        // get current price of the addons
        var order_price_addon = $(".order_price_addon").text();
        // get price of the clicked radio button from the rel attribute
        var add = $(this).children('option').attr('label');
        var name = $(this).attr('name');
        var val = $(this).val();


        if(val == "") {
            var price = parseInt(order_price_addon) - parseInt(add);
            removeSession(name);
        } else {
            if(isSession(name) == 0) {
                var price = parseInt(order_price_addon) + parseInt(add);
            }   
            setSession(name, val);              
        }

        $(".order_price_addon").html(price);    
        setSession('order_price_addon', price);         
        updateTotal();
});

a więc - przede wszystkim, gdy menu #add_ons select wywołuje „zmianę”, otrzymujemy do obliczeń pewne wartości z kilku elementów.

otrzymujemy atrybut label opcji z naszego select, który przechowuje wartość, która ma zostać dodana do sumy, nazwę selekcji do utworzenia sesji o tej nazwie i wartość, aby później sprawdzić, która z nich została wybrana.

teraz - sprawdzamy czy val == "" (co wskazywałoby, że wybrano opcję None) i odejmujemy kwotę od sumy jak również usuwamy sesję z nazwą selekcji.

Po tym zaczyna się problem - instrukcja else.

W przeciwnym razie - chcemy sprawdzić, czy funkcja isSession () o nazwie naszego selektora zwraca 0 czy 1 - jeśli zwraca 0 to dodajemy do sumy wartość przechowywaną w atrybucie label, ale jeśli zwraca 1 - to by sugerowało ta sesja już istnieje - wtedy zmienimy wartość tej sesji tylko poprzez jej odtworzenie - ale kwota nie zostanie do niej dodana.

Teraz funkcja isSession wygląda następująco:

function isSession(selector) {
    $.ajax({
        type: "POST",
        url: '/order.html',
        data: ({ issession : 1, selector: selector }),
        dataType: "html",
        success: function(data) {
            return data;
        },
        error: function() {
            alert('Error occured');
        }
    });
}

Teraz - problem polega na tym, że nie wiem, czy użycie "return" zwróci wynik funkcji - bo wydaje się, że nie działa - jeśli jednak wstawię sekcję "data" w success: do alert - wydaje się zwracać właściwą wartość.

Czy ktoś wie, jak zwrócić wartość z funkcji, a następnie porównać ją w następnej instrukcji?


Dzięki chłopaki - wypróbowałem to w następujący sposób:

function isSession(selector) {
    $.ajax({
        type: "POST",
        url: '/order.html',
        data: ({ issession : 1, selector: selector }),
        dataType: "html",
        success: function(data) {
            updateResult(data);
        },
        error: function() {
            alert('Error occured');
        }
    });
}

następnie funkcja updateResult ():

funkcja updateResult (dane) {wynik = dane; }

wynik - to zmienna globalna - którą następnie próbuję odczytać:

$("#add_ons select").change(function() {
        // get current price of the addons
        var order_price_addon = $(".order_price_addon").text();
        // get price of the clicked radio button from the rel attribute
        var add = $(this).children('option').attr('label');
        var name = $(this).attr('name');
        var val = $(this).val();


        if(val == "") {
            var price = parseInt(order_price_addon) - parseInt(add);
            removeSession(name);
        } else {
            isSession(name);
            if(result == 0) {
                var price = parseInt(order_price_addon) + parseInt(add);
            }   
            setSession(name, val);              
        }

        $(".order_price_addon").html(price);    
        setSession('order_price_addon', price);         
        updateTotal();
    });

ale z jakiegoś powodu - nie działa - jakiś pomysł?

user398341
źródło
Może pomóc rozwiązać ten problem: stackoverflow.com/questions/14220321/ ...
mirzaei.sajad

Odpowiedzi:

114

Problem polega na tym, że nie można zwrócić wartości z wywołania asynchronicznego, takiego jak żądanie AJAX, i oczekiwać, że zadziała.

Powodem jest to, że kod oczekujący na odpowiedź został już wykonany przed odebraniem odpowiedzi.

Rozwiązaniem tego problemu jest uruchomienie niezbędnych kod wewnątrz tej success:zwrotnego. W ten sposób uzyskuje dostęp datatylko wtedy, gdy jest dostępny.

function isSession(selector) {
    $.ajax({
        type: "POST",
        url: '/order.html',
        data: ({ issession : 1, selector: selector }),
        dataType: "html",
        success: function(data) {
            // Run the code here that needs
            //    to access the data returned
            return data;
        },
        error: function() {
            alert('Error occured');
        }
    });
}

Inną możliwością (która jest właściwie tym samym) jest wywołanie funkcji wewnątrz twojego success:wywołania zwrotnego, która przekazuje dane, gdy są one dostępne.

function isSession(selector) {
    $.ajax({
        type: "POST",
        url: '/order.html',
        data: ({ issession : 1, selector: selector }),
        dataType: "html",
        success: function(data) {
                // Call this function on success
            someFunction( data );
            return data;
        },
        error: function() {
            alert('Error occured');
        }
    });
}

function someFunction( data ) {
    // Do something with your data
}
user113716
źródło
12
MOŻESZ zwrócić wartość z żądania AJAX, ale dzieje się tak tylko wtedy, gdy ustawisz ją jako nieasynchroniczną (ustaw opcję async: false). W niektórych przypadkach posiadanie wywołania asynchronicznego nie jest wymagane. Więcej na temat jquery.ajax () doc api.jquery.com/jQuery.ajax , nie toAs of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated;
Adrien Be
50
„Nieasynchroniczne” można oczywiście nazwać również „synchronicznymi”;)
Charles Wood,
w obu sugerowanych przez ciebie metodach; to znaczy. uruchom funkcję z powodzeniem, wtedy musisz napisać wiele ajax dla różnych scenariuszy. to nie pomoże w tworzeniu globalnego wrappera Ajax, silnika.
wpcoder
Wygląda na to, że async: false jest teraz przestarzałe i całe przetwarzanie musi być wykonane w funkcjach wywołania zwrotnego.
Puneet Lamba
33

Istnieje wiele sposobów uzyskania odpowiedzi jQuery AJAX. Dzielę się z wami dwoma typowymi podejściami:

Pierwszy:

użyj async = false, a wewnątrz funkcji zwróć obiekt ajax-object, a później uzyskaj odpowiedź ajax-object.responseText

/**
 * jQuery ajax method with async = false, to return response
 * @param  {mix}  selector - your selector
 * @return {mix}           - your ajax response/error
 */
function isSession(selector) {
    return $.ajax({
        type: "POST",
        url: '/order.html',
        data: {
            issession: 1,
            selector: selector
        },
        dataType: "html",
        async: !1,
        error: function() {
            alert("Error occured")
        }
    });
}
// global param
var selector = !0;
// get return ajax object
var ajaxObj = isSession(selector);
// store ajax response in var
var ajaxResponse = ajaxObj.responseText;
// check ajax response
console.log(ajaxResponse);
// your ajax callback function for success
ajaxObj.success(function(response) {
    alert(response);
});

Druga:

użyj metody $ .extend i utwórz nową funkcję, taką jak ajax

/**
 * xResponse function
 *
 * xResponse method is made to return jQuery ajax response
 * 
 * @param  {string} url   [your url or file]
 * @param  {object} your ajax param
 * @return {mix}       [ajax response]
 */
$.extend({
    xResponse: function(url, data) {
        // local var
        var theResponse = null;
        // jQuery ajax
        $.ajax({
            url: url,
            type: 'POST',
            data: data,
            dataType: "html",
            async: false,
            success: function(respText) {
                theResponse = respText;
            }
        });
        // Return the response text
        return theResponse;
    }
});

// set ajax response in var
var xData = $.xResponse('temp.html', {issession: 1,selector: true});

// see response in console
console.log(xData);

możesz zrobić tak duży, jak chcesz ...

Neeraj Singh
źródło
Niezły pomysł, ale ajaxObj['responseText']nie istnieje, kiedy definiujeszvar ajaxResponse
mu3
Idealny!! Twoje pierwsze rozwiązanie uratowało mnie
Kallel Omar
druga metoda to 100% OK! ;)
Schalk Keun
7
Począwszy od jQuery 1.8, użycie async: false jest przestarzałe!
gatteo
11

Widziałem tutaj odpowiedzi i chociaż były pomocne, nie były one dokładnie tym, czego chciałem, ponieważ musiałem zmienić wiele mojego kodu.

To, co mi się udało, zrobiło coś takiego:

function isSession(selector) {
    //line added for the var that will have the result
    var result = false;
    $.ajax({
        type: "POST",
        url: '/order.html',
        data: ({ issession : 1, selector: selector }),
        dataType: "html",
        //line added to get ajax response in sync
        async: false,
        success: function(data) {
            //line added to save ajax response in var result
            result = data;
        },
        error: function() {
            alert('Error occured');
        }
    });
    //line added to return ajax response
    return result;
}

Nadzieja pomaga komuś

anakin

anakin
źródło
4
Właściwie po prostu wyłączasz async
Weijing Jay Lin,
5

Chociaż wszystkie podejścia dotyczące użycia async: falsenie są dobre z powodu jego dezaktualizacji i zablokowały stronę, dopóki żądanie nie wróci. Oto dwa sposoby, aby to zrobić:

1st: Zwróć całą odpowiedź ajax w funkcji, a następnie użyj donefunkcji do przechwycenia odpowiedzi, gdy żądanie zostanie zakończone. (ZALECANE, NAJLEPSZY SPOSÓB)

function getAjax(url, data){
    return $.ajax({
        type: 'POST',
        url : url,              
        data: data,
        dataType: 'JSON',
        //async: true,  //NOT NEEDED
        success: function(response) {
            //Data = response;
        }
    });
 }

ZADZWOŃ POWYŻEJ TAK:

getAjax(youUrl, yourData).done(function(response){
    console.log(response);
});

W PRZYPADKU WIELU POŁĄCZEŃ AJAX WYKORZYSTAJ $.when:

$.when( getAjax(youUrl, yourData), getAjax2(yourUrl2, yourData2) ).done(function(response){
    console.log(response);
});

2nd: Przechowuj odpowiedź w pliku cookie, a następnie poza wywołaniem Ajax pobierz wartość tego pliku cookie. (NIE ZALECANE)

        $.ajax({
            type: 'POST',
            url : url,              
            data: data,
            //async: false,    // No need to use this
            success: function(response) {
                Cookies.set(name, response);
            }
        });

        // Outside of the ajax call
        var response = Cookies.get(name);

UWAGA: W powyższym przykładzie jquery cookiesużywana jest biblioteka, która jest dość lekka i działa równie zgryźliwie. Oto link https://github.com/js-cookie/js-cookie

MR_AMDEV
źródło
3

Dodaj async: falsedo listy atrybutów. Zmusza to wątek javascript do czekania, aż zwrócona wartość zostanie pobrana przed przejściem dalej. Oczywiście nie chciałbyś tego robić w każdych okolicznościach, ale jeśli potrzebna jest wartość przed kontynuowaniem, to wystarczy.

Chuligan
źródło
4
Nigdy nie powinieneś ustawiać async: false. To blokuje wszystko na stronie na czas pobierania. Wiesz, co oznacza A w AJAX: asynchroniczny. Prawidłowa odpowiedź byłaby taka, że ​​OP musi success()poprawnie używać wywołania zwrotnego.
nietonfir
2
Przyznałam, że wszystko musi poczekać. W pewnych okolicznościach funkcja wywołująca może wymagać zwróconej wartości, takiej jak dodanie nowego rekordu i zwrócenie identyfikatora rekordu. Znając zasady, wiesz, kiedy można je złamać. Nigdy nie mów nigdy. Oto ktoś, kto się z tym zgadza. ( stackoverflow.com/questions/3880361/… )
Hoodlum,
1
@CharlesWood Wyłącznie dla tych, którzy nie mogą pojąć asynchronicznej natury Ajax.
nietonfir
1
@nietonfir: jeśli nigdy nie powinieneś używać, async: falsedlaczego jQuery zaimplementował tę opcję? Jeśli nie ładuję dużych ilości danych na stronę i po prostu obsługuję zdarzenie użytkownika, jest w porządku, że blokuje wszystko inne w krótkim czasie dla tego konkretnego użytkownika. nic w tym złego i nic złego. (jeśli zostanie użyty poprawnie, nie zablokuje niczego, ponieważ w tym konkretnym czasie nie będą wykonywane żadne inne akcje dla tego konkretnego użytkownika)
low_rents
1
@northkildonan Nie, nie jest w porządku. Żądanie synchronizacji AJAX jest nieprawidłowe. Blokuje cały wątek javascript czymś, czego nie możesz kontrolować. Nie masz kontroli nad tym, ile czasu może zająć przetworzenie żądania: połączenie może być zawodne, serwer może trwać dłużej niż oczekiwano, itp. Jedynym powodem , dla którego jest to w jQuery, jest to, że może być konieczne zapisanie danych na wyładowaniu strony (jedyne miejsce nie ma znaczenia, czy trwa to dłużej, ponieważ użytkownik wyraził już chęć opuszczenia strony). Wystarczy spojrzeć na testy jednostkowe jQuery…
nietonfir
3

To jest dość stare i brzydkie, nie rób tego. Powinieneś użyć callbacków: https://stackoverflow.com/a/5316755/591257
Miałem ten sam problem, rozwiązałem go w ten sposób, używając globalnego var. Nie jestem pewien, czy jest najlepszy, ale na pewno działa. W przypadku błędu otrzymasz pusty ciąg (myVar = ''), więc możesz to obsłużyć w razie potrzeby.

var myVar = '';
function isSession(selector) {
  $.ajax({
    'type': 'POST',
    'url': '/order.html',
    'data': {
      'issession': 1,
      'selector': selector
    },
    'dataType': 'html',
    'success': function(data) {
      myVar = data;
    },
    'error': function() {
      alert('Error occured');
    }
  });
  return myVar;
}
aesede
źródło
4
musisz również dodać async: falsetutaj, ponieważ w trybie asynchronicznym nie ma gwarancji, że datazostanie zapisany myVarprzed myVarzwróceniem.
low_rents
2
// Common ajax caller
function AjaxCall(url,successfunction){
  var targetUrl=url;
  $.ajax({
    'url': targetUrl,
    'type': 'GET',
    'dataType': 'json',
    'success': successfunction,
    'error': function() {
      alert("error");
    }
  });
}

// Calling Ajax
$(document).ready(function() {
  AjaxCall("productData.txt",ajaxSuccessFunction);
});

// Function details of success function
function ajaxSuccessFunction(d){
  alert(d.Pioneer.Product[0].category);
}

może to pomóc, utwórz wspólną funkcję AJAX i dołącz funkcję, która wywoła wywołanie Ajax po pomyślnym zakończeniu, patrz przykład

Binson
źródło
1

Z pomocą tutaj

function get_result(some_value) {
   var ret_val = {};
   $.ajax({
       url: '/some/url/to/fetch/from',
       type: 'GET',
       data: {'some_key': some_value},
       async: false,
       dataType: 'json'
   }).done(function (response) {
       ret_val = response;
   }).fail(function (jqXHR, textStatus, errorThrown) {
           ret_val = null;
       });
   return ret_val;
}

Mam nadzieję, że to komuś trochę pomoże.

Muhammad Nahid
źródło
Użycie async: false,jest prehistoryczne i jest przestarzałe od wersji jQuery v1.8, prawdopodobnie nikomu nie pomoże
Alon Eitan
-2

Cześć, spróbuj async: false w wywołaniu Ajax.

kathir
źródło