How to defer multiple ajax success callbacks? - javascript

In my Javascript, I have the following scenario:
call_A(success_A)
call_B(success_B)
function call_A(success){
// make ajax request
success(result)
}
function call_B(success){
//make ajax request
success(result)
}
function success_A(){
//set data to be used by success_B
}
function success_B(){
..do some stuff
}
I want to make both call_A and call_B one after the other so that ajax calls are made (to save time).
I do not have the option for changing call_A and call_B function headers, so the call to these function has to be made specifying the success callback function.
What I want is that regardless of which of the 2 ajax call finishes first, I want success_A get called before success_B, because B depends on A's data.
What is the best way of getting this done?

a_success= false;
b_success= false;
call_A(generalSuccess);
call_B(generalSuccess);
function call_A(success) {
// make ajax request
a_success = true;
success(result)
}
function call_B(success) {
//make ajax request
b_success = true;
success(result)
}
function generalSuccess() {
//assuming you are passing which a or b is called. set b_success or a_success is true
if (a_success == true && b_success == true) {
// use all variables you need and get the final result
} else if (a_success == true) {
// set your desired value into a global variable from a request
} else if (b_success == true) {
// set results to use from b request.
}
}

Related

Getting a value through a function in javascript using global variables

var voted;
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
voted = data.host;
console.log(voted);
});
console.log(voted);
So voted is undefined outside, however, it's defined properly inside the function.
I'm wondering how I can use the data.value outside the function. The only thing I can think of is using a global variable, however, it doesn't work as expected.
Edit: Need the IP outside of functions
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
voted(data.host);
});
function voted(ip) {
ip_voted = ip_array.indexOf(ip);
if (ip_voted > -1) {
window.location.href = "results";
}
}
if (choice && ip == '123123123') {
}
you can use this way
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
writeVoted(data.host);
});
function writeVoted(voted) {
console.log(voted);
}
or leave a synchronous call (I believe not be advisable)
async (default: true)
Type: Boolean
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success().
The reason it doesn't work out for you is that the call to getJSON is an asynchronous call. In sense it means that it is ripped out of the current flow and executed somewhere independently. Take a look at the comments I have added to your code below:
var voted;
//getJSON is executed right away - async
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
//This callback function executes when the remote request responds. The timeframe is variable.
voted = data.host;
console.log(voted);
});
//Gets executed right away - doesn't wait for getJSON to get the remote response.
//voted is probably still undefined.
console.log(voted);
What you need to to is add a function that continues your flow, as shown below:
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
voted(data.host);
});
function voted(ip) {
ip_voted = ip_array.indexOf(ip);
if (ip_voted > -1) {
window.location.href = "results";
}
verify(ip);
}
function verify(ip) {
if (choice && ip == '123123123') {
}
}
If you really need to use the data in a global variable, you could "wait" for the response - however I strongly advise against doing this:
var host, value;
var responseArrived = false;
$.getJSON("http://smart-ip.net/geoip-json?callback=?", function(data){
host = data.host;
value = data.value;
responseArrived = true;
});
while( !responseArrived ) {
//NOT A GOOD IDEA!
//Will continue to loop until the callback of getJSON is called.
//NOT A GOOD IDEA!
}
console.log(host);
console.log(value);

Wait for Json call to be completed in javascript

I am using the below json call in my javascript method
function go123(){
var cityName = "";
var temp = $.getJSON("https://abc.in/api/city?callback=?", args,function (data) {
if (data.properties.city != null){
cityName = data.properties.city;
check = true;
} else {
cityName = "NaN"
}
}); // end of my Json Call.
// my validation is done below
if(cityName != "NaN"){
return false;
} else {
// here I except the cityName to not be "" but be some value which is set as :cityName = data.properties.city;
return true;
}
} // end of my function
Now what problem I am facing is that before my Json call is compelete the next set of statements ( in the code below the line "// my validation is done below " ) is already executed.
I want to get the values set in my json call (cityName) and only once when the call is completed then only I want the next set of statements to be executed.
Please help me on this. Any advice/ideas/suggestions will be highly appreciated ! Thanks.
The function you passed into $.getJSON() is the callback run when the function completes successfully. All else being equal, stick the "rest of it" inside that method. If you can't do so, what you're after is called a jQuery Deferred. See http://www.erichynds.com/jquery/using-deferreds-in-jquery/ and http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ for code that looks like so:
var req = $.getJSON('blah', 'de', 'blah');
req.success(function(response){
// The request is done, and we can do something else
});
AJAX calls are asyncrhonous. They don't wait for the reply. They operate in the background and execute the code that follows it immediately after the call. Therefore, the data received in getJSON is not yet there when the operations below it are executed.
You can put the operations you want in the callback so that they get executed when the data is revceived:
function go123(callback){
var temp = $.getJSON("https://abc.in/api/city?callback=?", args,function (data) {
//execute the callback, passing it the data
callback(data);
});
}
//when you call go123, it get's back the result:
function goBefore123(){
//get our JSON
go123(function(data){
//when we get our data, evaluate
if (data.properties.city != null){
cityName = data.properties.city;
check = true;
alert('executed after returned');
afterCall();
} else {
cityName = "NaN"
}
});
alert('i am executed before anything else');
}
function afterCall(){
alert('im also executed after');
}
Calling an external url will take too much time, wait for the result
Check below
var jqxhr = $.getJSON("example.json", function() {
alert("success");
})
.success(function() { alert("second success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
http://api.jquery.com/jQuery.getJSON/
.success
http://api.jquery.com/jQuery.getJSON/

let synchronous code wait an asynchronous call

I have a form of which I catch the submit event. I have to wait for a $.post call in order to decide whether to submit it. I've tried this:
$('#my_form').submit(function(event){
var data = null;
$.post("/post/call").then(function(_data){
data = _data;
});
if ( $.isPlainObject(data) && data.status === 'ko' ) {
return false; // Do not submit the original form
} else {
// Submit the original form
}
});
But data results to be always null, also if _data is valorized, because $.post is an asynchrounous call. How can I wait for the $.post call to be completed?
EDIT: As wrote in the comments, I would like to avoid $.ajax({async: true}), because it freezes the page; is there any way to get the same effect without freezing the page?
You should have some sort of flag that says the form is to be submitted or not as well as that the ajax is processing. Then when the ajax call passes, call $('#my_form').submit() to send the form.
Loosely,
var validated = false;
$('#my_form').submit(function(event){
if (validated) {
return true;
}
$.post("/post/call").then(function(_data){
var data = _data;
if ( $.isPlainObject(data) && data.status === 'ko' ) {
// Do not submit the original form
} else {
validated = true;
$('#my_form').submit();
}
});
return false;
});
If you are using MVC / C#, and can use a Json request to access your web service, know the following.
$.getJSON
Is asynchronous
SOLUTION: $.ajax
Can be set to synchronous

Getting undefined via ajax JSON

when I check the log from Console using chrome browser, I keep getting sideType is undefined. It is not returning data to sideType variable.
when I put console.log(sideType); in the sideGroupData() function - it work fine without problem.
Code:
function sideGroupData(GroupID) {
$.getJSON("group_data.php",{GroupID:GroupID}, function(j){
return j;
});
}
function reloadProduct(productID) {
$.post("product.php", { productID:productID }, function(data) {
var sideType = sideGroupData(123);
console.log(sideType);
});
}
reloadProduct(999);
It's because you're running your call in a closure. The ajax call is being made asynchronously, which means that your code continues moving even though you're making an ajax call:
function setVar () {
var retVal = 1;
$.ajax(..., function(data){
retVal = data; //retVal does NOT equal data yet, it's still waiting
});
return retVal; //will return 1 every time because code doesn't wait for ajax
}
var someVar = setVar(); // will be 1
If you want to return that value, include a callback function to run when the data is returned, and run it with the data supplied, like so:
function sideGroupData(GroupID, callback){
$.getJSON('group_data.php', {GroupID: GroupID}, callback);
}
function reloadProduct(productID) {
$.post("product.php", { productID:productID }, function(data) {
sideGroupData(123, function(sideType){
console.log(sideType);
});
});
}
or, just make the call inside the function itself:
function reloadProduct(productID, groupId) {
var prod, sideType;
$.post("product.php", { productID:productID }, function(data) {
prod = data;
$.getJSON('group_data.php', {GroupID: groupId}, function(json){
sideType = json;
// you now have access to both 'prod' and 'sideType', do work here
});
});
}
the sidegroupdata() function call will return immediately - it'll trigger the ajax request and keep on executing. That means sideType is being assigned a null value, because sideGroupData doesn't actually explicitly return anything after the ajax call section.
Is there any reason you're doing an ajax request WITHIN an ajax request? Wouldn't it make more sense to modify the product.php page to return a data structure containing both that product ID AND the 'sidegroupdata' included in a single response?

javascript: returning a bool

I have written a jQuery / JS function which "runs a php query".
function runQuery(op){
if(op.type == "edit"){
var b = false;
if(op.id != "" && (op.fromSong || op.toSong || op.when || op.comment)){
$.post("processor.php", { id: op.id, type: "edit", fromSong: op.fromSong, toSong: op.toSong, when: op.when, comment: op.comment }, function(data){
if(data == true){
console.log(true);
b = true;
}else{
console.log(false);
b = false;
}
});
}
return b;
}
I want it to return true of false depending on what the server answers. I'm sure that the php script is working correctly and returning true or false correctly. But every time i run the function the console.log() outputs the correct value, unlike the variable b. It seems to alway be false. What am I doing wrong?
Since any .ajax() call ($.post is just a wrapper to $.ajax) runs asyncronously, your variable b will always return false. Best thing to "workaround" this is to pass in another callback:
function runQuery(op, callback){
if(op.type == "edit"){
if(op.id != "" && (op.fromSong || op.toSong || op.when || op.comment)){
$.post("processor.php", { id: op.id, type: "edit", fromSong: op.fromSong, toSong: op.toSong, when: op.when, comment: op.comment }, function(data){
if(data == true){
console.log(true);
callback.apply(this, [data]);
}else{
console.log(false);
callback.apply(this, [data]);
}
});
}
}
runQuery({
type: 'edit',
}, function(data) {
alert(data);
});
yes it is wrong.
$.post is done asynchronously, so b is set in the call back but returned before you reach the callback.
you should use $.ajax instead with method:"POST", and async: false
However it could be better to have a deisgn when you use the value of b in the callback only because async: false can freeze your browser.
Your function will return before the asynchronous request to the server has completed. Before you ask, it is both impractical and undesierable to make the call synchronous so that you can return true/false from your function. You might consider supplying a callback argument or arguments to your function:
function runQuery(op, success, failure){
// ...
if(data == true){
success();
}else{
failure();
}
// ...
}
runQuery('edit',
function () { alert('success!'); },
function () { alert('failure!'); }
);
This is a wrong way to do it. Ajax requests are asynchronous and not performed one after another as you expect them too. There is no way around that. You will have to redesign your code to nest ajax calls.
Something similar to this:
$.post("a.php", {function(data){
//1st check
$.post("b.php", {function(data){
//2nd check
$.post("c.php", {function(data){
//final actions
});
});
});
Only this way ajax calls will be stacked - the next will be performed after the previous.

Categories

Resources