Just wanting to populate myObj with data from within the get request. According to my console.log(myObj) everythings seems to be their but can't access. I'm sure their is a simple answer to this. Thanks.
function getInfo() {
var myObj = {};
$.get("http://ipinfo.io", function(response) {
myObj.city = response.city;
myObj.region = response.region;
}, "jsonp");
console.log(myObj.city); //undefined
return myObj;
}
var myStuff = getInfo(); //Object {} just as I expected obviously.
console.log(myStuff) // Object shows all my key value pairs but -->
console.log(myStuff.city); // undefined why?
It is more suitable to use promises. You can try something like this:
function getInfo() {
var dfd = $.Deferred();
$.get("http://ipinfo.io", function(response) {
myObj.city = response.city;
myObj.region = response.region;
dfd.resolve(myObj);
}, "jsonp");
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
getInfo().done(function(myStuff) {
console.log(myStuff);
console.log(myStuff.city);
});
With promises the code is one idea elegant.
$.get is an asynchronous operation which means that it returns immediately (without running the code in your callback function first). The callback will only be executed at some point in the future when the GET request is finished. In the meantime the code following the $.get call will be executed.
What you're seeing is a result of a specific execution order in which the GET request happened not to finish before the following code was executed. In other words you have a race condition.
In theory , if the GET request finished almost instantly, it would be possible for the callback to execute before your log statements and therefore not print undefined. This is highly unlikely, however, as the time it takes to execute log instructions are much(!) less than what it takes to execute the GET request.
To fix the issue you need to ensure that you're log statements are always run only after the GET request is finished. The idiomatic way to do this in JS is with callbacks - e.g. pass a function which contains the code to execute and call it from inside the response handler:
function getInfo(callback) {
var myObj = {};
$.get("http://ipinfo.io", function(response) {
myObj.city = response.city;
myObj.region = response.region;
callback(myObj);
}, "jsonp");
console.log(myObj.city); //undefined
}
getInfo(function(myStuff) {
console.log(myStuff)
console.log(myStuff.city);
});
It return undefine because the request didn't response yet then the function returned the value. Your request was asynchronous meaning your function wont wait for your get request. it would return what ever myObj is.
You can try something like
function getInfo(callback){
$.get(..., function(res){
var myObj = …;
callback(myObj);
}
}
when ever your request is finished, it would call the callback function and pass in the myObj. so you need to pass in a anonymous function that expect 1 argument to pass in the myObj from the response
getInfo(function(data){
//data should be myObj
});
Related
I have a javascript function that calls an AJAX, like this:
function addSquadronByID(id) {
$.ajax
({
type: "POST",
url: "server/get_squadron.php",
data: {
'id': id,
'counter': squadron_counter
},
cache: false,
success: function (data) {
squadron_counter++;
},
error: function () {
alert("AJAX error.");
}
});
}
}
Outside the document.ready, the variable is initialized like this var squadron_counter = 0;
This function perfectly works while I call it in the page, but if I try to use PHP to write it in the page, like this:
$list_squadrons = $DB->Execute($query);
while(!$list_squadrons->EOF){
$currentSquadron_id = $list_squadrons->fields["squadron_id"];
$currentSquadron_number = $list_squadrons->fields["squadrons"];
echo "addSquadronByID($currentSquadron_id);\n";
$list_squadrons->MoveNext();
}
The function writes into the document.ready() the correct calls, but squadron_counter is always zero, even if the function works. My only idea is that it works this way because javascript calls all the functions at once and does not wait to complete the first one before executing the second one, etc.. but how do I solve this?
HTML output as requested:
addSquadronByID(3, squadron_counter);
addSquadronByID(5, squadron_counter);
addSquadronByID(6, squadron_counter);
This is put into a
$( document ).ready(function() {
});
inside a <script> tag.
I think your idea about JS calling all functions without waiting for the first one to complete is in the right direction. This is called "asynchronous requests". Please refer to How to return the response from an asynchronous call? for a detailed explanation.
The idea is to send your 3 requests and then wait for all of them to complete before checking the value of your squadron_counter variable (or whatever data you have updated in your success callbacks).
Then if my understanding is correct, you do not know how to implement this waiting?
Since you are using jQuery, the implementation is super simple. Note first that your jQuery.ajax request returns a Deferred object. So simply keep a reference of the Deferred object created by each AJAX request you send. Then you could use for example jQuery.when with a callback in its then method to wait for all your requests to complete:
function addSquadronByID(id) {
return jQuery.ajax({ /* ... */ }); // returns a Deferred object.
}
var d1 = addSquadronByID(3),
d2 = addSquadronByID(5),
d3 = addSquadronByID(6);
jQuery.when(d1, d2, d3).then(
// callback executed on success of all passed Deferred objects.
function () {
console.log(squadron_counter);
}
);
Demo: http://jsfiddle.net/btjq7wuf/
I have the functions below:
(Normally I get the variable msg by doing some query on a XML Object)
function getMsg(callback) {
var msg = "test";
callback(msg);
}
function msgDone() {
var message = null;
getMsg(function(msg) {
message = msg;
});
return message; //Why is message undefined here?
}
My problem is that I get an undefined on message. I have tested the function getMsg(), and it returns the right value.
How will I make the msgDone to return the message that I get from callback? So that it doesn't return undefined?
Thanks
Why is message undefined here?
It won't be, in the code in the question, but my guess is that the real getMsg is an asynchronous operation. That is, when you call it, it starts the process of getting the message but that process completes later, not right away. (For instance, a typical ajax call is like this.)
In that case, the reason message is undefined in the location you marked is that the callback hasn't been called yet, so nothing has ever assigned to message. You can't return the result of an asynchronous call from a function; instead, you have to provide a callback mechanism of your own (simple callbacks, or promises, or similar). E.g.:
function getMsg(callback) {
// Do something asynchronous...
// It's done, call the callback
callback(/*...the data retrieved asynchronously...*/);
}
function msgDone(callback) {
getMsg(function(msg) {
// Presumably you do more processing here...
// ...and then call the callback
callback(msg);
});
}
Then, instead of:
var msg = msgDone();
doSomethingWith(msg);
doSomethingElseWith(msg);
you do:
msgDone(function(msg) {
doSomethingWith(msg);
doSomethingElseWith(msg);
});
I'm having an issue that is burning my head. Basically this is the scenario:
I have a callController() function, which just simple use the jQuery.load() method to load a controller, after loaded, I can play with the returning parameters.
Now... in one of my controllers there is a validation rule I need to check in order to to allow the user to execute certain functionality, however, I create a function like this:
function myValRule() {
var val = callController('blablabla'),
response = "";
val.done(function(data) {
//my business logic
response = something;
}
return response;
}
As you imagine, response, even if It has a value, it returns undefined, so I set a timeout and console.log() it and now it has a value, but I cannot make to return this value even if I put the return into the setTimeout(). So basically when the method call this function to validate it finds it empty.
Can you point me on some direction to solve this issue?
Remember this is asynchronous! The return response; is long gone by the time .done() is actually called.
if you need the value returned in this fashion, look at either supplying a callback function in your myValRule function (that would be called from within .done()) or maybe look at using the $.Deferred api so you can mimic what callController(...) is doing.
Here's an example of both scenarios (with example call to myValRule):
Callback argument
function myValRule(callback){
var val = callController('blablabla'),
val.done(function(data){
var response = /* something */;
callback(response);
});
}
myValRule(function(response){
// here you have response
});
Using $.Deferred
(I assume it's jQuery since there's a .done call)
function myValRule(){
var df = $.Deferred(),
val = callController('blablabla');
val.done(function(data){
var response = /*something */;
df.resolve(response);
}).fail(df.reject);
return df.promise();
}
myValRule().done(function(response){
// here you have response
});
What is the difference between the following two functions as far as promises are concerned?
var service = {
someFunction: function() {
return $http.get('url').then(function (response) {
return response;
});
},
someFunction2: function() {
return $http.get('url');
}
};
The second returns a promise so that the calling function (not shown in your code) can do something with it.
The first one does exactly the same thing, but it also uses the promise to define a function that will run then the response comes back. That function does (effectively) nothing, since when the HTTP response arrives, it returns to the calling function (then) which doesn't care about the response.
There is no difference - the identity function in the first example is not needed but doesn't cause any observable difference to outside.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I'm using the jQuery function $.getJSON to get some data from the server side and here is the code:
function (){
$.getJSON("someURI",function(result){
//this alert works fine
alert(result.msg)
});
// this prints the data as undefined
alert(result.msg);
}
how to change the scope of "result" returned from $.getJSON in order to make it global.. to make the second alert prints its value not to be undefined ??
You can't. AJAX is asynchronous meaning that you can access the result variable only inside the success callback. You could make it global, but remember that the line immediately following the $.getJSON call will be called much before the success callback executes rendering it useless.
So no global variables, consume the results of an AJAX call inside the callback:
function () {
$.getJSON('someURI', function(result){
// only here you can hope to consume the results of an AJAX call
alert(result.msg)
});
}
That's how AJAX works. The A in AJAX stands for asynchronous.
This is an asynchronous call.. So you must wait till the server responds...
In your case, the outer alert will be undefined as the server hasn't responded yet...
Also, the scope of result is limited to callback function, it's inaccessible...
You can do it like this though:
var myJSON;
var serverResponded = 0;
function () {
$.getJSON("someURI", function (result) {
//this alert works fine
myJSON = result.msg;
serverResponded = 1;
});
setTimeout(function () {
if (serverResponded) {
alert(myJSON);
}
}, 500);
}
The $.getJSON call is a shortcut to an Ajax call, and “Ajax” stands for “Asynchronous JavaScript and XML”.
Let's suppose you add var globalResult and that you perform a globalResult = result; in your success function. So, when you do a call to globalResult outside the callback, globalResult won't be assigned yet. So, if you really have to process it outside, you can check if it's assigned with a function called setInterval, but this is going too far.
save it into another variable something like this
function (){
var something;
$.getJSON("someURI",function(result){
//this alert works fine
alert(result.msg)
something = result
});
if you want it to be scoped outside your function wrapper, do something like this
var something;
function (){
$.getJSON("someURI",function(result){
//this alert works fine
alert(result.msg)
something = result
});