Confused with javascript global variable scope and update - javascript

I am trying to get a specific piece of data from from a json source. I have declared a global variable and try to update the global variable but it doesn't update correctly. Also, the order in which my debug alerts run is confusing.
<script>
//global variable
var latestDoorStatus = "initialized value"; //set value for debugging purposes
//debug alert which also calls the function
alert("Alert#1: call getDoorStatus = " + getDoorStatus("***********"));
function getDoorStatus(public_key) {
//get data in json form
var cloud_url = 'https://data.sparkfun.com/output/';
// JSONP request
var jsonData = $.ajax({
url: cloud_url + public_key + '.json',
data: {page: 1},
dataType: 'jsonp',
}).done(function (results) {
var latest = results[0];
//debug alert
alert("Alert #2: latestDoorStatus = " + latestDoorStatus);
//update the global variable
latestDoorStatus = latest.doorstatus;
//debug alert
alert("Alert #3: latestDoorStatus = " + latestDoorStatus);
//return the global variable
return latestDoorStatus;
});
alert("Alert #4: latestDoorStatus = " + latestDoorStatus);
}
</script>
When I run this in my browser I get the following behaviors:
First I get alert#4 (supposed to run at END of the script) with the initialized value of the global variable
then I get alert#1 as "undefined". This is supposed to be the result of calling the function getDoorStatus which should return an updated value of latestDoorStatus
then I get alert #2 as the initialized value of latestDoorStatus which makes sense since the global variable has not yet been updated
then I get alert #3 with the correct value of latestDoorStatus
The function is supposed to return the variable latestDoorStatus AFTER alert #3 (i.e. after global variable has been updated correctly) so I don't understand why alert #1 (which is supposed to have the returned value) is coming back undefined and why alert#4 which is supposed to run at the very end of the script is running first.

You are calling $.ajax asynchronously, and passing a callback function to done.
function makeRequest() {
$.ajax({ // An async Ajax call.
url: cloud_url + public_key + '.json',
data: {page: 1},
dataType: 'jsonp',
}).done(function (results) {
// this code is executed only after the request to cloud_url is finished.
console.log("I print second.");
});
console.log("I print first.");
}
The callback is called when the request is finished, and when depends entirely on how long the request to https://data.sparkfun.com/output/ takes. So the code after your Ajax call is executed immediately, we're not waiting for the http request to finish.
Your function getDoorStatus returns nothing, but your callback passed to done does. The thing you need to know is that you can't return anything from asynchronously executed functions. Well, you can return, but there will be nothing there to use the returned value.
So instead, do the things you want to do with the returned data from https://data.sparkfun.com/output/ in the callback passed to done.
function getDoorStatus(public_key) {
//get data in json form
var cloud_url = 'https://data.sparkfun.com/output/';
// JSONP request
var jsonData = $.ajax({
url: cloud_url + public_key + '.json',
data: {page: 1},
dataType: 'jsonp',
}).done(function (results) {
// latestDoorStatus = results[0]; // Not a good practice.
// Instead:
showDoorStatus(results[0]);
});
}
function showDoorStatus(status) {
document.getElementById("door-status").innerText = status;
// Or something like this.
}
getDoorStatus("***********");
And somewhere in your HTML:
<p id="door-status"></p>

.done() will be called after the response of the AJAX request got received!
1) getDoorStatus() is called from inside alert() at top of code => #4 shown. It does not matter that the function is defined below and not above.
2) alert() at top of code is called & getDoorStatus() does not directly return a value => #1 shown with undefined.
3) AJAX response returned, .done() function gets called => #2 and #3 are shown.

Related

multiple ajax async not in order and need synchronous behavior

Sorry, My first language is not English. I am not sure that if I explain my question properly.
My code is like a main function have two ajax functions (Use ajax function to get foursquare API)
main(){
ajax1();
ajax2();
all other codes
}
the ajax2() function has to get result from ajax1() as input and then return result(actually result was pushed in to global array).
all other codes should be processed after two ajax functions are finished. I tried the asyn: false but it is not working. My html file include newest jquery like this
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js" ></script>
I try the jquery function $.when().done() function and the first ajax works. However, the second ajax() function was in the for loop. The for loop will destroy the mechanism of $.when().done() function:
first ajax: in firstjson function
Second ajax: in transfer function
function firstjson(tmpName,tmpLoc,PhotoJson,foursq){
return $.ajax({
type: 'GET',
url: foursq,
dataType: 'jsonp',
success: function(json) {
for (i = 0; i < 3; i++) {
var resultname = json['response']['venues'][i].name;
var resultlocation = json['response']['venues'][i].location;
var resultlat = resultlocation.lat;
var resultlng = resultlocation.lng;
var tmpmarker = new google.maps.LatLng(resultlat,resultlng)
tmpName.push(resultname);
tmpLoc.push(tmpmarker);
var resultid = json['response']['venues'][i].id;
var tmpPhotoJason = 'https://api.foursquare.com/v2/venues/'+ resultid +'/photos?';
PhotoJson.push(tmpPhotoJason);
}
}
});
}
function transfer(PhotoJson,PhotoURL){
for (i = 0; i < 3; i++) {
return $.ajax({
type: 'GET',
url: PhotoJson[i],
dataType: 'jsonp',
success: function(json) {
resultphoto = json['response']['photos']['items'];
photoprefix = resultphoto[i].prefix;
photopresuffix = resultphoto[i].suffix;
photourl = photoprefix+"150x150" + photopresuffix;
PhotoURL.push(photourl);
}
});
}
}
$.when(firstjson(tmpName,tmpLoc,PhotoJson,foursq)).done(function(){
alert("test1");
$.when(transfer(PhotoJson,PhotoURL).done(function(){
console.log(PhotoURL);
all other codes!!!!
});
});
//PhotoURL is global array
So the first "when" function work properly. alert("test1") work after the firstjson was done. However the for loop inside transfer function will break the when function. How can I fix the problem. Please help me. I will appreciate you can give me any related information. Thanks!!!
This will execute ajax2 after ajax1
function anotherMethod(){
//Here you do all that you want to do after the last $ajax call
}
main(){
firstjson(tmpName,tmpLoc,PhotoJson,foursq)
.then(transfer(PhotoJson,PhotoURL))
.then(anotherMethod);
}
As you are returning a promise from the first with the "return $ajax..."
So you organice your code like this:
in methods with ajax calls you return the call as you are doing now
return $.ajax();
that returns a promise that you chain.
And you put what you want to do in another method so you call it in the last "then".
Non-Blocking Example
You should use non-blocking code. You can turn async off (async: false) but this can easily be done in a non-blocking manor using callback functions.
function main(){
$.ajax({ // First ajax call (ajax1)
url: "first/ajax/url",
type: "GET", // POST or GET
data: {}, // POST or GET data being passed to first URL
success: function(x){ // Callback when request is successfully returned
// x is your returned data
$.ajax({ // Second ajax call (ajax2)
url: "second/ajax/url",
type: "GET", // POST or GET
data: {
thatThing: x
}, // POST or GET data passed to second URL
success: function(y){
// y is your second returned data
// all other codes that use y should be here
}
});
}
})
}
This would be the non-blocking approach, nest your function within "success" callback functions. Nest ajax2 within ajax1's "success" callback to ensure that ajax2 is not executed before ajax1 has returned and nest your "all other codes" inside the "success" callback of ajax2 to ensure they are not executed until ajax2 has returned.
Blocking Example
If you absolutely must (please avoid at all cost) you can disable async which will block all JavaScript code from executing until the ajax has returned. This may cause your browser to temporarily freeze until the ajax request has returned (depending on the browser).
function main(){
var x = ajax1();
var y = ajax2(x);
window["y"] = y; // push to global as you requested but why?
// All other codes that can now use y
}
function ajax1(){
var x;
$.ajax({
url: "first/ajax/url",
async: false,
type: "GET", // POST or GET,
data: {}, // POST or GET data being passed to first URL
success: function(r){x=r}
});
return x;
}
function ajax2(x){
var y;
$.ajax({
url: "second/ajax/url",
async: false,
type: "GET", // POST or GET,
data: {
thatThing: x
}, // POST or GET data being passed to second URL
success: function(r){y=r}
});
return y;
}
Once again I stress, try not to disable async that will cause your code to block and is BAD code. If you absolutely 100% have to for some reason than than it can be done but you should attempt to learn how to write non-blocking code using callbacks as the first example does.
Social Network Example
Now I'll do an example of an ajax call to get an array of your friends IDs, and then a series of ajax calls to get each of your friends profiles. The first ajax will get the list, the second will get their profiles and store then, and then when all profiles have been retrieved some other code can be ran.
For this example, the url https://api.site.com/{userID}/friends/ retrieves an Object with a list of friends IDs for a particular user, and https://api.site.com/{userID}/profile/ gets any users profile.
Obviously this is a simplified api as you will probably need to first establish a connection with a apikey and get a token for this connection and the token would likely need to be passed to the api uris but I think it should still illustrate the point.
function getFriends(userID, callback){
$.ajax({
url: "https://api.site.com/"+userID+"/friends/",
success: function(x){
var counter = 0;
var profiles = [];
for(var i=0;i<x.friendIDs.length;i++){
$.ajax({
url: "https://api.site.com/"+x.friendIDs[i]+"/profile/",
success: function(profile){
profiles.push(profile);
counter++;
if(counter == x.friendIDs.length) callback(profiles);
}
});
}
}
});
}
getFreinds("dustinpoissant", function(friends){
// Do stuff with the 'friends' array here
})
This example is "Non-blocking", if this example were done in a "blocking" way then we would ask for 1 friends profile, then wait for its response, then request the next and wait and so on. If we had hundreds of friends you can see how this would take a very long time for all ajax calls to complete. In this example, which is non-blocking, all requests for profiles are made at the same time (within 1ms) and then can all be returned at almost exactly the same time and a counter is used to see if we have gotten responses from all the requests. This is way way way faster than using the blocking method especially if you have lots of friends.

jQuery ajax request only returns value on second call

I'm trying to get data from a php using jQuery's $.ajax method.
This is my code right now:
var ajaxresult = null;
function myFunc() {
$.ajax('ajaxtest.php',{
type: 'get',
data: '',
success: function(data) {
ajaxresult = data;
}
});
console.log(ajaxresult);
}
$('button').click(function(){
myFunc();
})
My problem is this:
The first time I call myFunc() (when I click the button) it logs null to the console, after that if I click again it returns the expected value.
What could cause this and how could I fix it to return the expected value the first time it's called?
Ajax is asynchronous, so the first time you click, the console log happens before the ajax call has completed, and it logs null.
The second time you click, the same thing happens, but the variable is global, so it now holds the value from the previous ajax call, and that's what's logged, the value from the previous call, not the value from the current call.
It should look more like this, the data is only available inside the callback
function myFunc() {
$.ajax({
url : 'ajaxtest.php',
type : 'GET',
data : '',
success: function(data) {
var ajaxresult = data;
console.log(ajaxresult);
}
});
}
$('button').click(myFunc);

Jquery: Variable not initialized in callback?

I have the following code snippet in Javascript-Jquery:
var result = "";
$.ajax({
type: 'POST',
url: 'update.php',
data: { 'val': $val }
})
.done(function(data) {
alert(data); // shows right response
result = data;
alert(result); // shows right response
});
alert(result); // shows nothing
Even though I initialized result in the callback, I get nothing when I alert the result variable (it is still "")? Why is this?
This is because the ajax call is run asynchronously. Just because the second alert is after the ajax call, you still have to either a: write a callback method to fire when the call completes or, b: complete the ajax call synchronously. See jquery ajax documentation for the async property and its description.
Is is simple. The alert(result) code is executed before the done callback. So, the result variable is empty. The done callback is called asynchronously after the alert call.
Hope it helps.
This becasue the mode of ajax now you use is the Asynchronous ...i have a example for you that it's as follow:
var result = "";
$.ajax({
type: 'POST',
url: 'update.php',
data: { 'val': $val' }
}).done(function(data) {
alert(1, data); // shows right response
result = data;
alert(2, result); //shows right response
});
alert(3, result) // shows nothing
if you want to use the Synchronous...look at the doc for async variable
i hope it's useful to you:)

Javascript value is returned from webservice but will not show unless a breakpoint is used

I have a javascript function that calls a web service. The data comeback (I see the Jason return in FireBug) the value is blank when I attempt to use it unless I set a break point. With a break point set the value can be used, without it is not available.
Here is a snippet of the offending call.
function getTheNote(noteCode){
var _myNote = "";
var theID = $('#CustNo').val();
var myDTO = { 'theID': theID, 'noteCode': noteCode, };
var toPass = JSON.stringify(myDTO);
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "AR_Cust_Mgt.aspx/getNote",
data: toPass,
success: function (data) {
_myNote = data.d;
}
});
//setTimeout(_myNote += _myNote, 120000);
//for(var x = 0; x < 200000; x++){}
//return _myNote;
alert(_myNote);
}
Originally I was sending the value back to a calling function the return statement is where I would set my break point and the data would be returned, without nothing. Now you can see I attempted to use an alert inside the function with the same results.
With a break point I get a value without I get nothing, I have even attempted to use some delays.
Please help.
The ajax call is asynchronous. Anything you want to do with the result needs to be in your anonymous function success: function(data) { ... or the anonymous function needs to call other functions to do stuff.
As it is coded now, $.ajax will be called, the script execution continues on before the ajax call returns.
small change, big difference: you are not calling alert IN the succes function
success: function (data) {
_myNote = data.d;
alert(_myNote);
}

javascript & jQuery scope question

I have the following method:
function priceRange(FESTIVALID){
jQuery.ajax({
url : '/actions/festheads.cfc?method=getPriceRangeByGUID',
type : 'POST',
data : 'FESTIVALID='+FESTIVALID,
dataType: 'json',
success : function(data) {
console.info("AJAX:qPrices",data.MINPRICE);
formatedPriceRange = '$ '+data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
}//success
});//ajax;
//
return formatedPriceRange;
};
The second console.info correctly displays the formatedPriceRange,
but outside the function is undefined.
how can I access this variable out side the priceRange function?
Thanks
It's normal, that's how AJAX works. It's asynchronous, meaning that the jQuery.ajax function returns immediately and in this case formatedPriceRange hasn't yet been assigned a value and once the server responds (which can be for example 10 seconds later), the success callback is invoked and the variable is assigned a value.
So always consume the results of your AJAX requests inside the success callback function.
You also have the possibility to pass the async: false option to your jQuery.ajax call which will perform a synchronous request to the server and block until the result is retrieved. Obviously this will lead to your browser freezing during the execution of the request. So it would no longer be AJAX (Asynchronous Javascript And Xml) but SJAX (Synchronous Javascript and Xml).
You have to make sure that the AJAX request finishes before you access the price range data.
You need to expose the price range data outside the scope of the success function.
Here's how you can do it:
function priceRange(FESTIVALID, callback) {
jQuery.ajax({
url: '/actions/festheads.cfc?method=getPriceRangeByGUID',
type: 'POST',
data: 'FESTIVALID=' + FESTIVALID,
dataType: 'json',
success: function(data) {
console.info("AJAX:qPrices", data.MINPRICE);
formatedPriceRange = '$ ' + data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
callback.call(this, formatedPriceRange);
} //success
}); //ajax;
}
var myFestivalID = 1;
priceRange(myFestivalID, function(priceRange) {
// this code runs when the ajax call is complete
alert('The formatted price range is:' + priceRange);
});
how can I access this variable out
side the priceRange function?
Like Darin said, you have to use your results in the success callback function.
Assuming you're using your current function like this:
var range = priceRange(festivalId);
// ... doing stuff with range variable
You'll want reorganize your code so that anything you do with the range variable stems from the success callback. For example, you can create a function to handle updating the UI with the new range:
function handleRangeVariabe(range) {
/// ... do stuff with range variable
}
Call it from success:
success: function(data) {
console.info("AJAX:qPrices",data.MINPRICE);
formatedPriceRange = '$ '+data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
handleRangeVariable(formatedPriceRange);
}
Flower the steps of sample Code:
//declare function
function priceRange(FESTIVALID, functionCallBack){
//1º step
jQuery.ajax({
url : '/actions/festheads.cfc?method=getPriceRangeByGUID',
type : 'POST',
data : 'FESTIVALID='+FESTIVALID,
dataType: 'json',
success : function(data) {
//3º step, because this function will only trigger when server responds to request
//handle data in other function
functionCallBack(data);
}//success
});//ajax;
//more code
//2º step
//no return value, because this method no know when the data will return of server
//return formatedPriceRange;
};
var formatedPriceRange;
//using function
princeRange(1 , function(data){
console.info("AJAX:qPrices",data.MINPRICE);
formatedPriceRange = '$ '+data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
});

Categories

Resources