Javascript Ajax save result of onreadystatechange in global variable
-
24-05-2021 - |
Question
I'm trying to write a script to retrieve a WOEID and interface with the Yahoo Weather API. I'm constructing a URL based on latitude and longitude values from stuff in a database I'm using, and can do this perfectly fine.
However, when it comes to storing that URL as a string that I can use in other functions, I'm having trouble. After some initial reading it seems to be a problem to do with onreadystatechange and scope, but I can't seem to get my head around it to be able to store my variable.
Here is my code so far:
//<![CDATA[
var latitude = "";
var longitude = "";
var yahooAppID = "";
var yql = "";
//example yahoo request
//http://where.yahooapis.com/geocode?q=38.898717,+-77.035974&gflags=R&appid=SKUTk24k
function getLatLng() {
var routeID = 5;
var get = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
get.open('POST','process.php', true)
get.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
get.send('command=fetch&rid='+routeID);
get.onreadystatechange = function(){
if(get.readyState==4 && get.status == 200) {
os = eval('(' + get.responseText + ')');
latitude = os.start.lat;
longitude = os.start.lng;
//var yql = 'select * from flickr.places where lat='+latitude+' and lon='+longitude;
yql = "select * from flickr.places where lat=" +latitude+ " and lon="+longitude;
}
document.write(yql);
}
document.write(yql);
}
function test() {
getLatLng();
}
//]]>
The first document.write(yql);
seems to produce the correct string, but the second does not, so I know that the value has not stuck.
Thanks in advance if anyone can help.
Solution
You're not looking at a scoping issue — rather, a timing issue. AJAX requests (at least the way you've configured it) happen asynchronously, so the rest of your script will execute while the AJAX request is loading. So yql
won't be updated until the very end.
Also, warning: by the time the request completes, you can no longer use document.write
. Use alert()
or DOM manipulation.
Life cycle looks like this:
- Script is executed normally
- Anonymous function is bound to
onreadystatechange
- readyState changes from "unsent" to "headers received" to "loading" to "done". Your function gets called every time, but you only set
yql
when the ready state is "done." - readyState is done, and you generate
yql
.
So, just call your processing function from inside the if:
if(get.readyState==4 && get.status == 200) {
os = get.responseXML;
//find lat + lng
yql = "select * from flickr.places where lat=" +latitude+ " and lon="+longitude;
process(yql); //here!
}
function process(yql) {
alert(yql); //do something more useful eventually
}