Call functions for ajax request inside callback

Asked

Viewed 1,435 times

1

Within a function callback() one click required to make at least 3 requests.

I’ve separated that into three functions: (func1(), func2() e func3()) and each of them makes a request ajax ($.get) returning to me true or false. If the func1() return true to func2() can be called and if the func2() return true to func3() can be called. If any of the func() return me false I cannot proceed with the func next.

How can I do that, why this way it is not returning true or false, it is returning undefined.

Link in jsfiddle: Code

$('#chamar').bind('click',
            function () {
                $('#form').validator().on('submit', function (e) {
                    if (e.isDefaultPrevented()) {
                        // handle the invalid form...
                    } else {

                    if(func1()==false){
                            //aqui ele ja deveria finalizar e não fazer a proxima requisição
                        alert("Função 1 falhou");
                    }

                     if(func2()==false){
                            //aqui ele ja deveria finalizar e não fazer a proxima requisição
                        alert("Função 2 falhou");
                    }

                    if(func3()==false){
                            //aqui ele ja deveria finalizar e não fazer a proxima requisição
                        alert("Função 3 falhou");
                    } 
                        alert("Todas as requisições foram feitas");
                    }
                })


            });

function func1() {

        $.get('consulta1.php?type=dado&action=get', {
                id: $('#id').val(),

            },function (e) {
                e = $.parseJSON(e);
                if (e[0].status) {
                    alert("DEU VERDADEIRO");
                    return true;
                } else {
                    alert("DEU FALSO");
                    return false;
                }
            }).fail(function () {
            alert("DEU FALSO");
            return false;
        });
    }

function func2() {

        $.get('consulta2.php?type=dado&action=get', {
                id: $('#id').val(),

            },function (e) {
                e = $.parseJSON(e);
                if (e[0].status) {
                    alert("DEU VERDADEIRO");
                    return true;
                } else {
                    alert("DEU FALSO");
                    return false;
                }
            }).fail(function () {
            alert("DEU FALSO");
            return false;
        });
    }

function func3() {

        $.get('consulta3.php?type=dado&action=get', {
                id: $('#id').val(),

            },function (e) {
                e = $.parseJSON(e);
                if (e[0].status) {
                    alert("DEU VERDADEIRO");
                    return true;
                } else {
                    alert("DEU FALSO");
                    return false;
                }
            }).fail(function () {
            alert("DEU FALSO");
            return false;
        });
    }

3 answers

2

It keeps returning undefined because the ajax requests are asynchronous, so they are only executed much later, however the function has already ended because it did not wait for the request to be completed. That’s the principle of asymchronism.

Consider the following identical structure to the one you are using:

function func1() {
  $.get(url, { dados }, function (e) { 
      ... 
      return ...;
  }).fail(function () {
    ...
    return ...;
  });

  //<----- Este é o valor que está a ser retornado, que é undefined pois a função não fica 
  //bloqueada à espera que o pedido get termine, simplesmente faz o pedido e continua. 
  //Se ficasse bloqueada à espera então era um pedido síncrono.
}

The solution to get the values of each order and make decisions based on that is to pass callbacks with what you intend to do when the order ends.

Applying this pattern to this func1 would look like this:

function func1(callback /*callback passado aqui*/) {
  $.get(url, { dados }, function (e) { 
      ...
      callback(true); //chamar o callback com true que indica sucesso
  }).fail(function () {
      ...
      callback(false); //chamar o callback com false que indica não sucesso
  });
}

And now when you call func1 passes a function as callback which receives as the first parameter a boolean indicating whether it succeeded or not:

func1(function (resultado) {
    alert(resultado); //vem true ou falso com base no resultado do pedido ajax
});

Applying this idea to your code:

function func1(callback) {
    $.get('consulta1.php?type=dado&action=get', 
        { id: $('#id').val() },
        function (e) {
            e = $.parseJSON(e);
            callback(e[0].status?true:false);
        }).fail(function () {
            callback(false);
        });
}

function func2(callback) {
    $.get('consulta2.php?type=dado&action=get', 
        { id: $('#id').val() },
        function (e) {
            e = $.parseJSON(e);
            callback(e[0].status?true:false);
        }).fail(function () {
            callback(false);
        });
}

function func3(callback) {
    $.get('consulta3.php?type=dado&action=get', 
        { id: $('#id').val() },
        function (e) {
            e = $.parseJSON(e);
            callback(e[0].status?true:false);
        }).fail(function () {
            callback(false);
        });
}

And the click becomes:

$('#form').validator().on('submit', function (e) {
    if (e.isDefaultPrevented()) {
        // handle the invalid form...
    } else {
        func1( function(resultado1){
            if (!resultado1){
                alert("Função 1 falhou");
            }
            else {
                func2( function(resultado2){
                    if (!resultado2){
                        alert("Função 2 falhou");
                    }
                    else {
                        func3( function(resultado3){
                            if (!resultado3){
                                alert("Função 3 falhou");
                            }
                            else {
                                alert("Todas as requisições foram feitas");
                            }
                        });
                    }
                });
            }
        });
    }
});

$('#chamar').bind('click', function () {
    $("#form").submit();
});

Note that each subsequent call increases the level of chaining of functions within functions. This was the purpose of creating the Promises, in which chaining is done by calling then at the end of each Promise which does not nest the threads and becomes simpler to use.

Also the form validation function should not be set within the button click or it accumulates several handlers clicks what make the code run more and more times as it clicks.

Looking for your functions func1, func2 and func3 I see they’re the same except for url. Then simplify and generalize a function for the three:

function funcN(url, seletor, callback) {
    $.get(url, 
        { id: $(seletor).val() },
        function (e) {
            e = $.parseJSON(e);
            callback(e[0].status?true:false);
        }).fail(function () {
            callback(false);
        });
}

Now you can use this function for all three orders by changing only the url. I put the seletor as a parameter also if you want to be able to call to another element other than just the #id.

The use would be:

$('#form').validator().on('submit', function (e) {
    if (e.isDefaultPrevented()) {
        // handle the invalid form...
    } else {
        funcN( function('consulta1.php?type=dado&action=get','#id',resultado1){
            if (!resultado1){
                alert("Função 1 falhou");
            }
            else {
                funcN( function('consulta2.php?type=dado&action=get','#id',resultado2){
                    if (!resultado2){
                        alert("Função 2 falhou");
                    }
                    else {
                        funcN( function('consulta3.php?type=dado&action=get','#id',resultado3){
                            if (!resultado3){
                                alert("Função 3 falhou");
                            }
                            else {
                                alert("Todas as requisições foram feitas");
                            }
                        });
                    }
                });
            }
        });
    }
});

$('#chamar').bind('click', function () {
    $("#form").submit();
});
  • Hello Isac thank you for answering. I did using this approach but it turns out that it is going into some kind of loop. When I click the button for the first time it gives the error "Function 1 failed". When I click the button a second time it appears 2 times the error "Function 1 failed", when I click the button for 3 time it gives the error 3 times "Function 1 failed" and so on. What can it be?

  • I looked at Chrome’s Developer Tools and it’s like it’s repeating the requests because it has several. When I click the second time, it makes two requests. When I click the third time it makes 3 requests and so on.

  • @L.J That’s why every time the #chamar is clicked sets a new click Handler, something that has passed me unnoticed in your code. What you want to do is set the $('#form').validator().on('submit' out of the click of #chamar and at the click of #chamar just send the form by doing $('#form').submit(). The goal of the button #chamar is validate and submit the form if it is valid right?

  • That.. before sending I need to check if the form is valid. I just use the 'Submit' pq I need to validate the fields and check if everything is ok. So much so that my form action is empty. The form is submitted by func1, func2 and func3. Then to use Validator I have to pass the ide of the form. Validator()...I don’t know if I could do with $("#call"). Validator().

  • So I don’t need to use $('#form'). Submit(). I submit through the functions' ajaxes 1, func2 and func3.

0

I believe that using a Promise be more appropriate in your.

var ajax = function (method, url, data) {
  return new Promise(function (resolve, reject) {
    var request = new XMLHttpRequest();
    request.open(method, url);
    request.addEventListener("readystatechange", function (evt) {
      if (request.readyState == 4) {
        if (request.status == 200) {
          if (request.response[0].status) {
            resolve("Retorno: Verdadeiro");
          } else {
            reject("Retorno: Falso");
          }
        } else {
          reject("Retorno: Error => " + request.statusText);
        }
      }
    });
    request.responseType = "json";
    request.send(data);
  });
}

var data = { id: document.getElementById("id").value };
ajax("GET", "consulta1.php?type=dado&action=get", data)
.then(function (msg) {
  console.log(msg);
  return ajax("GET", "consulta2.php?type=dado&action=get", data);
})
.then(function (msg) {
  console.log(msg);
  return ajax("GET", "consulta3.php?type=dado&action=get", data);
})
.then(function (msg) {
  console.log(msg);
})
.catch(function (msg) {
  console.log(msg);
})
<input id="id" type="hidden" value="123" />

  • How would this implementation look using $.post or $.get from jquery...without using pure javascript, it’s like?

  • @L.J in place of the XMLHttpRequest use the $.ajax, but I don’t see why you should do it. Or for another, if you want to use a library with a API more modern, use the Axios

  • is pq I already use jquery in the whole project, then put only this request with pure js gets kind of weird...rsrs. I’ll test this implementation and tell you about it.

  • i have 3 functions: func1, func2 and func3 as I call them in this implementation?

0

You can call func2 in func1, and the func3 in func2, similarly to a callback.

It will be as follows:

$('#chamar').bind('click',
  function () {
    $('#form').validator().on('submit', function (e) {
      if (e.isDefaultPrevented()) {
        // handle the invalid form...
      } else {
         func1();
      }
  }        
});

Implementation of func1():

function func1() {
  $.get('consulta1.php?type=dado&action=get', {
    id: $('#id').val(),
  }, function (e) {
    e = $.parseJSON(e);
    if (e[0].status) {
      alert("DEU VERDADEIRO");
      // Chama a func2()
      func2();
      return;
    } else {
      alert("DEU FALSO");
      return;
    }
  }).fail(function () {
    alert("DEU FALSO");
    return;
  });
}

Impementation of func2():

function func2() {
  $.get('consulta2.php?type=dado&action=get', {
    id: $('#id').val(),
  },function (e) {
    e = $.parseJSON(e);
    if (e[0].status) {
      alert("DEU VERDADEIRO");
      // Chama a func3();
      func3();
      return;
    } else {
      alert("DEU FALSO");
      return;
    }
  }).fail(function () {
    alert("DEU FALSO");
    return;
  });
}
  • I tested its implementation and is occurring the same error that happens in the implementation of Isac. When I click on the button it repeats the same "GAVE TRUE" depending on the amount of time I clicked on the button. If I click once it appears once the Alert, if once again it appears twice and so on.

  • On Cick after function Else 1(func2) I put an Alert: Alert("All requests have been made"); It turns out that because it is an asynchronous request it executes this Alert before running Alert within the function. All right. This I understood. But the fact is that this Alert repeats itself depending on the number of clicks on the button. That is, when I click on the 1 time appears 1 time the message Alert("All requests were made"); when I click for 2 time appears the message Alert ("All requests were made"); when I click for the third time appears 3 times the message of Alert.

  • I looked at Chrome’s Developer Tools and it’s like it’s repeating the requests because it has several. When I click the second time, it makes two requests. When I click the third time it makes 3 requests and so on.

  • How strange, I will give a search to know what is happening.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.