jquery - valor de retorno usando resultado ajax em caso de sucesso

95

Eu tenho um pequeno problema com a função jquery $ .ajax ().

Eu tenho um formulário onde cada clique no botão de rádio ou seleção no menu suspenso cria uma variável de sessão com o valor selecionado.

Agora - eu tenho um dos menus suspensos que tem 4 opções - o primeiro (com rótulo Nenhum) tem um valor = "" os outros têm seus ids.

O que eu quero que aconteça é a opção Nenhum (com valor em branco) para remover a sessão e outra para criar uma, mas somente se a sessão com este nome de seleção específico ainda não existir - já que todas as outras opções têm a mesma quantidade atribuída a ela - está apenas indicando qual foi selecionado.

Não tenho certeza se isso faz sentido - mas dê uma olhada no código - talvez isso o torne mais claro:

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

então - em primeiro lugar, quando o menu #add_ons select aciona "mudança", obtemos alguns valores de alguns elementos para cálculos.

obtemos o atributo label da opção de nosso select que armazena o valor a ser adicionado ao total, nome do select para criar sessão com este nome e valor para depois verificar qual foi selecionado.

agora - verificamos se val == "" (o que indicaria que a opção Nenhum foi selecionada) e deduzimos o valor do total e também removemos a sessão com o nome do select.

Depois disso, é onde o problema começa - instrução else.

Do contrário - queremos verificar se a função isSession () com o nome de nosso seletor retorna 0 ou 1 - se retornar 0, então adicionamos ao total o valor armazenado no atributo label, mas se retornar 1 - isso sugere aquela sessão já existe - então nós apenas mudamos o valor desta sessão recriando-a - mas a quantidade não é adicionada a ela.

Agora a função isSession se parece com isto:

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

Agora - o problema é - que não sei se o uso de "return" retornará o resultado da função - já que não parece funcionar - no entanto, se eu colocar os "dados" na seção success: no alerta - parece retornar o valor correto.

Alguém sabe retornar o valor da função e depois compará-lo na próxima instrução?


Obrigado pessoal - tentei da seguinte forma:

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

então a função updateResult ():

função updateResult (dados) {resultado = dados; }

resultado - é a variável global - que estou tentando ler:

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

mas por algum motivo - não funciona - alguma ideia?

user398341
fonte
possível duplicata de Como retornar a resposta de uma chamada AJAX?
Bergi,
Isso pode ajudar a resolver este problema: stackoverflow.com/questions/14220321/…
mirzaei.sajad

Respostas:

114

O problema é que você não pode retornar um valor de uma chamada assíncrona, como uma solicitação AJAX, e esperar que funcione.

O motivo é que o código que está aguardando a resposta já foi executado no momento em que a resposta é recebida.

A solução para esse problema é executar o código necessário dentro do success:retorno de chamada. Dessa forma, ele está acessando o dataapenas quando estiver disponível.

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

Outra possibilidade (que é efetivamente a mesma coisa) é chamar uma função dentro de seu success:retorno de chamada que transmite os dados quando eles estão disponíveis.

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
fonte
11
Você PODE retornar um valor de uma solicitação AJAX, mas isso apenas se você torná-la não assíncrona (defina a opção async: false). Em alguns casos, ter uma chamada assíncrona não é um requisito. Mais sobre jquery.ajax () doc api.jquery.com/jQuery.ajax , não issoAs of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated;
Adrien Be
48
"Não-assíncrono" também pode ser referido como "síncrono";)
Charles Wood
em ambos os métodos que você sugeriu; ie. execute a função com sucesso, então você terá que escrever múltiplos ajax para diferentes cenários. isso não ajudará na criação de um mecanismo, wrapper de ajax global.
wpcoder
Parece que async: false está obsoleto e todo o processamento precisa ser feito nas funções de retorno de chamada.
Puneet Lamba
31

Existem muitas maneiras de obter uma resposta jQuery AJAX. Estou compartilhando com vocês duas abordagens comuns:

Primeiro:

use async = false e dentro da função, retorne ajax-object e depois obtenha a resposta 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 o método $ .extend e crie uma nova função 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);

você pode torná-lo tão grande quanto quiser ...

Neeraj Singh
fonte
Boa ideia, mas ajaxObj['responseText']não existe quando você está definindovar ajaxResponse
mu3
Perfeito!! sua primeira solução me salvou
Kallel Omar
o segundo método é 100% A OK! ;)
Schalk Keun
7
A partir do jQuery 1.8, o uso de async: false está obsoleto!
gatteo
10

Eu vi as respostas aqui e, embora úteis, elas não eram exatamente o que eu queria, já que tive que alterar muito meu código.

O que funcionou para mim foi fazer algo assim:

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

Espero que ajude alguém

anakin

anakin
fonte
4
Na verdade, basta desligar o assíncrono
Weijing Jay Lin
4

Embora todas as abordagens relacionadas ao uso de async: falsenão sejam boas por causa de sua depreciação e travou a página até que a solicitação voltou. Portanto, aqui estão 2 maneiras de fazer isso:

1º: Retorne a resposta ajax inteira em uma função e então faça uso da donefunção para capturar a resposta quando a solicitação for concluída. (RECOMENDADO, A MELHOR MANEIRA)

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

LIGUE PARA O ACIMA ASSIM:

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

PARA VÁRIAS CHAMADAS AJAX, USE $.when:

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

2º: Armazene a resposta em um cookie e, fora da chamada ajax, obtenha o valor do cookie. (NÃO 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: No exemplo acima, a jquery cookiesbiblioteca é usada. É bastante leve e funciona bem. Aqui está o link https://github.com/js-cookie/js-cookie

MR_AMDEV
fonte
3

Adicione async: falseà sua lista de atributos. Isso força o thread javascript a esperar até que o valor de retorno seja recuperado antes de prosseguir. Obviamente, você não gostaria de fazer isso em todas as circunstâncias, mas se um valor for necessário antes de continuar, ele o fará.

Hoodlum
fonte
3
Você nunca deve definir async: false. Isso bloqueia tudo na página durante a recuperação. Você sabe o que significa A em AJAX: Assíncrono. A resposta adequada seria que OP precisa usar o success()retorno de chamada corretamente.
nietonfir 01 de
2
Reconheci o fato de que tudo tem que esperar. Sob certas circunstâncias, a função de chamada pode precisar de um valor retornado, como adicionar um novo registro e precisar que um ID de registro seja retornado. Depois de conhecer as regras, você sabe quando elas podem ser violadas. Nunca diga nunca. Aqui está outra pessoa que concorda. ( stackoverflow.com/questions/3880361/… )
Hoodlum
1
@CharlesWood Apenas para aqueles que não conseguem entender a natureza assíncrona do ajax.
nietonfir
1
@nietonfir: se você nunca deveria usar, async: falsepor que o jQuery implementaria essa opção? se eu não carregar grandes quantidades de dados na página e apenas manipular um evento de usuário, não há problema em bloquear todo o resto no curto espaço de tempo para aquele usuário específico. nada de errado e nada de ruim nisso. (se usado corretamente, não bloqueará nada porque, naquele momento específico, nenhuma outra ação para aquele usuário em particular ocorrerá)
low_rents
1
@northkildonan Não, não está tudo bem. Uma solicitação de sincronização AJAX é inválida. Ele bloqueia o thread javascript completo com algo que você não pode controlar. Você não tem controle sobre a quantidade de tempo que pode demorar para processar o pedido: a conexão pode não ser confiável, o servidor pode demorar mais tempo do que o esperado, etc. A única razão pela qual ele está em jQuery é que você pode precisar para salvar os dados no descarregamento da página (o único lugar que realmente não importa se demorar mais, pois o usuário já manifestou o desejo de sair da página). Basta olhar para os testes de unidade do jQuery ...
nietonfir
3

Isso é muito antigo e feio, não faça isso. Você deve usar callbacks: https://stackoverflow.com/a/5316755/591257
Tive o mesmo problema, resolvi dessa forma, usando uma var global. Não tenho certeza se é o melhor, mas certamente funciona. Em caso de erro, você obtém uma string vazia (myVar = ''), para que possa lidar com isso conforme necessário.

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
fonte
3
você também precisa adicionar async: falseaqui, porque no modo assíncrono não é garantido que dataseja salvo myVarantes de myVarser retornado.
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);
}

pode ajudar, criar uma função de chamada ajax comum e anexar uma função que invoca quando for bem-sucedida a chamada ajax, veja o exemplo

Binson
fonte
1

Com ajuda daqui

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 isso ajude alguém em algum lugar um pouco.

Muhammad Nahid
fonte
O uso de async: false,é pré-histórico e está obsoleto desde o jQuery v1.8. Provavelmente não ajudará ninguém
Alon Eitan
-2

Olá, tente async: false em sua chamada ajax ..

Katir
fonte