jquery - valor de retorno usando el resultado ajax en caso de éxito

95

Tengo un pequeño problema con la función jquery $ .ajax ().

Tengo un formulario donde cada clic en el botón de opción o selección del menú desplegable crea una variable de sesión con el valor seleccionado.

Ahora - tengo uno de los menús desplegables que tienen 4 opciones - el primero (con etiqueta Ninguno) tiene un valor = "" otros tienen sus ID.

Lo que quiero que suceda es la opción Ninguno (con valor en blanco) para eliminar la sesión y otra para crear una, pero solo si la sesión con este nombre de selección específico no existe, ya que todas las demás opciones tienen la misma cantidad asignada. - solo indica cuál fue seleccionado.

No estoy seguro de si eso tiene sentido, pero eche un vistazo al código, tal vez esto lo aclare:

$("#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();
});

así que, en primer lugar, cuando el menú de selección #add_ons activa "cambio", obtenemos algunos valores de algunos elementos para los cálculos.

obtenemos el atributo de etiqueta de la opción de nuestra selección que almacena el valor a agregar al total, nombre de la selección para crear sesión con este nombre y valor para luego verificar cuál fue seleccionada.

ahora - verificamos si val == "" (lo que indicaría que se ha seleccionado la opción Ninguno) y deducimos la cantidad del total, además de eliminar la sesión con el nombre de la selección.

Después de esto es donde comienza el problema - declaración else.

De lo contrario, queremos verificar si la función isSession () con el nombre de nuestro selector devuelve 0 o 1; si devuelve 0, agregamos al total el valor almacenado en el atributo de etiqueta, pero si devuelve 1, eso sugeriría esa sesión ya existe, entonces solo cambiamos el valor de esta sesión recreándola, pero la cantidad no se le agrega.

Ahora la función isSession se ve así:

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');
        }
    });
}

Ahora, el problema es que no sé si el uso de "return" devolverá el resultado de la función, ya que no parece funcionar, sin embargo, si pongo los "datos" en la sección éxito: en la alerta: parece devolver el valor correcto.

¿Alguien sabe cómo devolver el valor de la función y luego compararlo en la siguiente declaración?


Gracias chicos, lo he probado de la siguiente manera:

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');
        }
    });
}

luego la función updateResult ():

función updateResult (datos) {resultado = datos; }

resultado - es la variable global - que luego estoy tratando de leer:

$("#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();
    });

pero por alguna razón, no funciona, ¿alguna idea?

user398341
fuente
Puede ayudar a resolver este problema: stackoverflow.com/questions/14220321/…
mirzaei.sajad

Respuestas:

114

El problema es que no puede devolver un valor de una llamada asincrónica, como una solicitud AJAX, y esperar que funcione.

La razón es que el código que espera la respuesta ya se ha ejecutado cuando se recibe la respuesta.

La solución a este problema es ejecutar el código necesario dentro de la success:devolución de llamada. De esa manera accede al dataúnico cuando está disponible.

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');
        }
    });
}

Otra posibilidad (que es efectivamente lo mismo) es llamar a una función dentro de su success:devolución de llamada que pasa los datos cuando están disponibles.

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
}
usuario113716
fuente
11
PUEDE devolver un valor de una solicitud AJAX, pero eso solo si lo hace no asíncrono (establezca la opción async: false). En algunos casos, no es un requisito tener una llamada asincrónica. Más sobre jquery.ajax () doc api.jquery.com/jQuery.ajax , no esoAs of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated;
Adrien Be
48
"No asincrónico", por supuesto, también se puede denominar "sincrónico";)
Charles Wood
en ambos métodos que sugirió; es decir. ejecute la función con éxito, luego debe escribir múltiples ajax para diferentes escenarios. esto no ayudará a crear una envoltura global de ajax, motor.
wpcoder
Parece que async: false ahora está en desuso y todo el procesamiento debe realizarse en las funciones de devolución de llamada.
Puneet Lamba
31

Hay muchas formas de obtener la respuesta de jQuery AJAX. Comparto con ustedes dos enfoques comunes:

Primero:

use async = false y dentro de la función devuelva ajax-object y luego obtenga la respuesta 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);
});

Segundo:

use el método $ .extend y cree una nueva función como 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);

puedes hacerlo tan grande como quieras ...

Neeraj Singh
fuente
Buena idea, pero ajaxObj['responseText']no existe cuando estás definiendovar ajaxResponse
mu3
¡¡Perfecto!! tu primera solución me salvó
Kallel Omar
El segundo método es 100% ¡OK! ;)
Schalk Keun
7
A partir de jQuery 1.8, el uso de async: false está obsoleto.
gatteo
10

Vi las respuestas aquí y, aunque útiles, no eran exactamente lo que quería, ya que tuve que alterar gran parte de mi código.

Lo que funcionó para mí fue hacer algo como esto:

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

La esperanza ayuda a alguien

Anakin

Anakin
fuente
4
En realidad, simplemente apaga async
Weijing Jay Lin
4

Aunque todos los enfoques con respecto al uso de async: falseno son buenos debido a su obsolescencia y atascaron la página hasta que regrese la solicitud. Por lo tanto, aquí hay 2 formas de hacerlo:

1 °: Devuelve la respuesta ajax completa en una función y luego usa la donefunción para capturar la respuesta cuando se completa la solicitud (RECOMENDADO, LA MEJOR MANERA)

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

LLAME AL ANTERIOR COMO ASÍ:

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

PARA MÚLTIPLES LLAMADAS AJAX, HAGA USO DE $.when:

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

2do: Almacene la respuesta en una cookie y luego, fuera de la llamada ajax, obtenga ese valor de cookie (NO RECOMENDADO)

        $.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);

NOTA: En el ejemplo anterior jquery cookiesse usa la biblioteca. Es bastante liviana y funciona igual de ágil. Aquí está el enlace https://github.com/js-cookie/js-cookie

MR_AMDEV
fuente
3

Agregue async: falsea su lista de atributos. Esto obliga al hilo de javascript a esperar hasta que se recupere el valor de retorno antes de continuar. Obviamente, no querrá hacer esto en todas las circunstancias, pero si se necesita un valor antes de continuar, lo hará.

Matón
fuente
3
Nunca deberías establecer async: false. Esto bloquea todo en la página mientras dure la recuperación. Ya sabes lo que significa la A en AJAX: asincrónico. La respuesta adecuada sería que OP necesita usar la success()devolución de llamada correctamente.
nietonfir
2
Reconocí el hecho de que todo tiene que esperar. En determinadas circunstancias, la función de llamada puede necesitar un valor devuelto, como agregar un nuevo registro y necesitar que se devuelva un ID de registro. Una vez que conozca las reglas, sabrá cuándo se pueden romper. Nunca digas nunca. Aquí hay alguien más que está de acuerdo. ( stackoverflow.com/questions/3880361/… )
Hoodlum
1
@CharlesWood Solo para aquellos que no pueden comprender la naturaleza asíncrona de ajax.
nietonfir
1
@nietonfir: si nunca debería usar, async: false¿por qué jQuery habría implementado esta opción? Si no cargo grandes cantidades de datos en la página y solo manejo un evento de usuario, está bien que bloquee todo lo demás en el corto período de tiempo para ese usuario en particular. nada malo y nada malo en eso. (si se usa correctamente, no bloqueará nada porque en ese momento en particular no se producirán otras acciones para ese usuario en particular)
low_rents
1
@northkildonan No, no está bien. Una solicitud de sincronización AJAX es incorrecta. Bloquea el hilo de javascript completo con algo que no puede controlar. No tiene control sobre la cantidad de tiempo que puede tomar procesar la solicitud: la conexión puede no ser confiable, el servidor puede demorar más de lo esperado, etc. La única razón por la que está en jQuery es que es posible que deba guardar datos en la descarga de la página (el único lugar en el que realmente no importa si tarda más, ya que el usuario ya expresó su deseo de abandonar la página). Solo mire las pruebas unitarias de jQuery ...
nietonfir
3

Esto es bastante antiguo y feo, no hagas esto. Debe usar devoluciones de llamada: https://stackoverflow.com/a/5316755/591257
Tuve el mismo problema, lo resolví de esta manera, usando una var global. No estoy seguro de si es el mejor, pero seguramente funciona. En caso de error, obtiene una cadena vacía (myVar = ''), por lo que puede manejarla según sea necesario.

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
fuente
3
también debe agregar async: falseaquí, porque en el modo asincrónico no se garantiza que datase guarde myVarantes de que myVarse devuelva.
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);
}

puede ayudar, cree una función de llamada ajax común y adjunte una función que invoque cuando tenga éxito la llamada ajax, vea el ejemplo

Binson
fuente
1

Con ayuda de aqui

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

Espero que esto ayude un poco a alguien en algún lugar.

Muhammad Nahid
fuente
El uso de async: false,es prehistórico y está en desuso desde jQuery v1.8, probablemente no ayudará a nadie
Alon Eitan
-2

Hola, prueba async: false en tu llamada ajax.

kathir
fuente