Wait for data from external API - javascript

I am attempting to interface with the Google Maps API marking locations based on latitude and longitude data. I would also like to get time zone information based off of this latitude and longitude. To do this, I am using another external API that takes in the latitude and longitude and returns the time off-set. My issue, however, is that this time data returns after the page is loaded.
What is the best way to then add this information to the page after the page has loaded for the user? I started out thinking about using postback, but after doing some research, I don't think that's the right method for my problem.

In browsers, JavaScript allows you to contact a server after a page is loaded. This is known as an asynchronous request, the first 'A' in 'AJAX' (Asynchronous Java and XML).
The X can be a bit of a misnomer, as people will happily pass whole chunks of HTML, or JSON (AJAJ?) or other forms of data instead of XML through this mechanism.
I would always use a framework (my personal choice being JQuery) to perform the operation, as the framework writers will have done the job of making it all work cross-browser for you.
You could use this:
http://api.jquery.com/jQuery.get/
or if the return data is JSON,
http://api.jquery.com/jQuery.getJSON/
This function, part of JQuery, will execute a callback function once the data is loaded. Your callback function can then use the JQuery selectors to find and update the elements in question.
If you update your question with specific code examples I can be more specific with my response.
Edit after seeing code example:
It looks like your problem is actually one of working out the order of code execution. Your code follows this pattern (somewhat simplified and a touch rearranged):
var startTimeZone;
jQuery(document).ready(function($) {
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + start_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
startTimeZone = parsed_json.data.time_zone[0].utcOffset;
console.log("Callback: " + startTimeZone);
},
error: function(parsed_json) {
}
});
});
console.log("Main:" + startTimeZone);
Firstly, there isn't a need to wrap the ajax command in the document ready callback - that only needs to be done once for the whole of your code, around wherever the entry point is. (I assume that it was an attempt to delay the execution until after the following code.) (There is more to learn here as well - JQuery gives you more than one event to help initialise your code and work with the DOM, see window.onload vs $(document).ready() for a brief description)
If you ran the snippet above, you'd find that the console log would probably show:
Main: Undefined
Callback: [StartTimeZone]
where [StartTimezone] is the response from the server. The ajax command is asynchronous, meaning it goes off and does its thing, taking as long as it needs, leaving the code after it to run as if nothing had happened. When it's finished it calls the 'success' or 'error' callback appropriately. So the 'main' console log is called before the variable has been defined. After that, the callback is hit by the response to the ajax call - so the StartTimeZone is output.
If you're new to callbacks or used to a language that doesn't support them or use them very often (like PHP), you may expect or want the code to pause at the ajax call, then run the callback, then carry on with the rest of the code. Obviously this isn't the case.
In this simple situation I would simply move the code to process the timezone into the callback, but your code has a further wrinkle - you need two values, which you seem to need to retrieve with separate calls.
In this case, we need to make sure we have both values before we run the code that uses them. How can we do this?
A simple solution would be:
var startTimeZone;
var endTimeZone;
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + start_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
startTimeZone = parsed_json.data.time_zone[0].utcOffset;
getEndTimeZone();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
function getEndTimeZone() {
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + end_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
endTimeZone = parsed_json.data.time_zone[0].utcOffset;
console.log(endTimeZone);
processTimeZones();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
}
function processTimeZones() {
var timeZoneDifference = (endTimeZone * 3600000) - (startTimeZone * 3600000);
// Do the rest of your processing here
}
Functions aren't run until they are called. Also, functions in JavaScript have access to the variables in their containing scope (this means that the functions have access to startTimeZone and endTimeZone, which are defined outside the functions themselves.)
The code above will call getEndTimeZone on success of the first ajax call. getEndTimeZone then uses an ajax call to get the end time zone, then calls the process function on success. This function definitely has access to the variables you need.
Of course, we're waiting in a queue now for two requests to be processed. We could speed things up a little by calling both at the same time, calling the process function with both, then figuring out if we have the data we need before doing the processing:
var startTimeZone;
var endTimeZone;
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + start_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
startTimeZone = parsed_json.data.time_zone[0].utcOffset;
processTimeZones();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + end_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
endTimeZone = parsed_json.data.time_zone[0].utcOffset;
console.log(endTimeZone);
processTimeZones();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
function processTimeZones() {
if (startTimeZone != undefined && endTimeZone != undefined)
{
var timeZoneDifference = (endTimeZone * 3600000) - (startTimeZone * 3600000);
// Do the rest of your processing here
}
}
Whichever ajax call returns first will call the process function. However, one of the variables will be undefined so the if condition will fail and the function will silently return. When the second result comes in, both variables will be set. Now the if condition will be met and the processing code will run.
There are 1001 ways to skin the proverbial cat, but these should hopefully get you started using the callbacks effectively.
Of course, all this is ignoring the fact that you've put the ajax calls in a for loop. Things could get funky if each iteration of the processing you need to do is dependent on the order it happens - the ajax calls could return in potentially any order. As you're plotting a route, this may well be the case.
If so, you could split your code into two phases - a loading phase and a processing phase. Run all the callbacks in the loading phase, then when you have all the data move to the processing phase and place the markers on the map. You could store the data in an array of objects.
There are a few ways to detect the end of the loading phase. One would be a counter that you increment every time you make an ajax call and decrement every time you get a success. You'd be able to create a loading progress bar using the same counter.
Also you could display a message to the user if any of the calls failed, with a link to restart the process. (Trivially this would reload the whole page, but you could restart the loading stage.)
HTH. By all means shout if you need further help.

Related

Adding delay to Javascript function call by calling python script

I've looked into a great deal of solutions which make use of setInterval and setTimeout, however I thought I could give it a go adding a delay between function calls with use of a python script.
To explain the code:
I have a dropdown menu which contains the football matches being played today. When a user selects an option from this dropdown list i.e. it detects a change, then it executes a bunch of code to update the page with the relevant information.
Within this function I have another function liveCommentaryCall()
which uses AJAX to get the latest updates in the football match selected from the dropdown menu.
Of course I need to call this every X seconds to update the webpage
regarding the latest events.
At the end of the function I make an AJAX POST request to a
specific URL /delayRequest, which I then have that route in flask
simply perform a sleep()and return.
After this I then call the function liveCommentaryCall()again to
restart the update procedure.
JAVASCRIPT
$("#teamDropdownSelector").change(function(){
.
.
.
function liveCommentaryCall(){
alert("called");
.
. // bunch of code to update the page
.
$.ajax({
url: "/delayRequest",
type: "POST",
data: JSON.stringify(""),
success: function(response) {
alert("RESPONSE RECIEVED");
},
error: function(delayError) {
alert("Something's gone wrong!");
}
});
liveCommentaryCall();
}
//Now out of the function scope.
//Below is the first time the liveCommentaryCall function gets called.
liveCommentaryCall();
});
PYTHON
#app.route("/delayRequest", methods=['POST', 'GET'])
def delay():
time.sleep(10)
return;
However, opposed to calling the function, it running, then having a delay of 10 seconds before being called again, the webpage just peppers me with "called" alerts, meaning liveCommentaryCall is just getting called instantly on loop somewhere?
I can't see anywhere in code which should be causing this, which makes me think theres some underlying principle I'm overlooking.
Question
Is the error in the fact that I cant use a python script like this, or am I just not coding this idea correctly?
Instead of implementing liveCommentaryCall recursively, you can use the setInterval function in the script:
<script>
setInterval("liveCommentaryCall()",1000); //call every second
function liveCommentaryCall(){
.
. // bunch of code to update the page
.
$.ajax({
url: "/delayRequest",
type: "POST",
data: JSON.stringify(""),
success: function(response) {
alert("RESPONSE RECIEVED");
},
error: function(delayError) {
alert("Something's gone wrong!");
}
});
}
</script>

Put ajax response attribute in to a variable for Google Books cover image

I am trying to put a url from an ajax response into a variable in jquery.
I have written the following code:
var thumb = $.ajax({
dataType: 'json',
url: 'https://www.googleapis.com/books/v1/volumes?q=isbn:' + isbn,
success: function(response){
return $(response).volumeInfo.imageLinks.thumbnail;
}}).responseText;
It was my understanding from looking at other answers that I must add .responseText at the end, or the code will continue without waiting for the ajax response.
However, thumb variable remains undefined.
I tried implementing the following solution with relevant changes (As I am passing only one ISBN at a time, there shouldn't be an array. The response should contain only one imageLinks.thumbnail url), but I cannot seem to catch the response correctly.
I looked into other answers, especially this one, but I am still not clear about how to reach the ajax response.
$.ajax is asynchronous, meaning the code will execute completely and the success callback will be fired at a later time.
var thumb is evaluated immediately. Do some reading on "callbacks" and "promises" to get more familiar with this topic.
A solution to your issue is:
function setThumbnail(thumbnail){
// this will evaluate later, when the ajax returns success
console.log('thumbnail gotten!');
var thumb = thumbnail; // do something with in in this function
}
$.ajax({
dataType: 'json',
url: 'https://www.googleapis.com/books/v1/volumes?q=isbn:' + isbn,
success: function(response){
setThumbnail($(response).volumeInfo.imageLinks.thumbnail);
}
});
// This line will evaluate immediately and carry on
console.log('ajax executed');
I threw in some logs for you to help you understand the order of execution here.
I would also note that $(response) looks odd to me, without testing it I think it should probably be just response.volumeInfo....
console.log(response) in the success callback to make sure you understand what data you are getting back.

ajax call won't execute synchronously

I have built a weather website that calls the flickr API 1st, then calls the yahoo API for the weather. The problem is that the data from the ajax call - from the yahoo API is not here in time for the page to load its content.
Some of the things I have used to try and slow the ajax call down:
setTimeout
wrapping the entire function that $.ajax(success: ) calls into another function, wrapping it in setTimeout
taking the callback function out of $.ajax(success: ), and putting into the $.ajax(complete: ) param
taking the data object that $.ajax(success: ) passes in, and copying that to another var, then going outside of ajax call and putting the function that handles the data inside of $.ajaxComplete(), passing new object var
There are more ways that I have tried to go about this, but I have been at it for 3 days and cannot find a solution. Can someone please help me here
Here is a link to the project
My Weather App On codeine.io
function RunCALL(url)
{
var comeBack = $.ajax({
url: url,
async: false,
dataType:"jsonp",
crossDomain: true,
method: 'POST',
statusCode: {
404: function() {console.log("-4-4-4-4 WE GOT 404!");},
200: function() {console.log("-2-2-2-2 WE GOT 200!");}},
success: function(data){
weatherAndFlickrReport(data);},
error: function(e) {console.log(e);}
});
}
Are you using jQuery? If so, you have to chain your callbacks. Which, at a high level, would looks something like:
//You might want to use .get or .getJSON, it's up to what response you're expecting...
$.getJSON('https://example.com/api/flickr', function(response) {
//This your callback. The URL would end up being https://example.com/api/yahoo/?criteria=lalalalala
$.getJSON('https://example.com/api/yahoo/', { criteria: response.propertyYouWant}, function(yahooResponse) {
//Do something with your response here.
});
});
Edit: I have updated your snippet with a working solution (based on the above AJAX requests) which now shows both your JSON objects ready for consuming. Looky here.

JQuery - Looping a .load() inside a 'for' statement

I'm not sure if this will actually be possible, since load() is an asynchronous method, but I need some way to basically Load several little bits of pages, one at a time, get some data included in them via JavaScript, and then send that over via Ajax so I can put it on a database I made.
Basically I get this from my page, where all the links I'll be having to iterate through are located:
var digiList = $('.2u');
var link;
for(var i=0;i<digiList.length;i++){
link = "http://www.digimon-heroes.com" + $(digiList).eq(i).find('map').children().attr('href');
So far so good.
Now, I'm going to have to load each link (only a specific div of the full page, not the whole thing) into a div I have somewhere around my page, so that I can get some data via JQuery:
var contentURI= link + ' div.row:nth-child(2)';
$('#single').load('grabber.php?url='+ contentURI,function(){
///////////// And I do a bunch of JQuery stuff here, and save stuff into an object
///////////// Aaaand then I call up an ajax request.
$.ajax({
url: 'insertDigi.php',
type: 'POST',
data: {digimon: JSON.stringify(digimon)},
dataType: 'json',
success: function(msg){
console.log(msg);
}
////////This calls up a script that handles everything and makes an insert into my database.
}); //END ajax
}); //END load callback Function
} //END 'for' Statement.
alert('Inserted!');
Naturally, as would be expected, the loading takes too long, and the rest of the for statement just keeps going through, not really caring about letting the load finish up it's business, since the load is asynchronous. The alert('Inserted!'); is called before I even get the chance to load the very first page. This, in turn, means that I only get to load the stuff into my div before I can even treat it's information and send it over to my script.
So my question is: Is there some creative way to do this in such a manner that I could iterate through multiple links, load them, do my business with them, and be done with it? And if not, is there a synchronous alternative to load, that could produce roughly the same effect? I know that it would probably block up my page completely, but I'd be fine with it, since the page does not require any input from me.
Hopefully I explained everything with the necessary detail, and hopefully you guys can help me out with this. Thanks!
You probably want a recursive function, that waits for one iteration, before going to the next iteration etc.
(function recursive(i) {
var digiList = $('.2u');
var link = digiList.eq(i).find('map').children().attr('href') + ' div.row:nth-child(2)';
$.ajax({
url: 'grabber.php',
data: {
url: link
}
}).done(function(data) {
// do stuff with "data"
$.ajax({
url: 'insertDigi.php',
type: 'POST',
data: {
digimon: digimon
},
dataType: 'json'
}).done(function(msg) {
console.log(msg);
if (i < digiList.length) {
recursive(++i); // do the next one ... when this is one is done
}
});
});
})(0);
Just in case you want them to run together you can use closure to preserve each number in the loop
for (var i = 0; i < digiList.length; i++) {
(function(num) { < // num here as the argument is actually i
var link = "http://www.digimon-heroes.com" + $(digiList).eq(num).find('map').children().attr('href');
var contentURI= link + ' div.row:nth-child(2)';
$('#single').load('grabber.php?url=' + contentURI, function() {
///////////// And I do a bunch of JQuery stuff here, and save stuff into an object
///////////// Aaaand then I call up an ajax request.
$.ajax({
url: 'insertDigi.php',
type: 'POST',
data: {
digimon: JSON.stringify(digimon)
},
dataType: 'json',
success: function(msg) {
console.log(msg);
}
////////This calls up a script that handles everything and makes an insert into my database.
}); //END ajax
}); //END load callback Function
})(i);// <-- pass in the number from the loop
}
You can always use synchronous ajax, but there's no good reason for it.
If you know the number of documents you need to download (you can count them or just hardcode if it's constant), you could run some callback function on success and if everything is done, then proceed with logic that need all documents.
To make it even better you could just trigger an event (on document or any other object) when everything is downloaded (e.x. "downloads_done") and listen on this even to make what you need to make.
But all above is for case you need to do something when all is done. However I'm not sure if I understood your question correctly (just read this again).
If you want to download something -> do something with data -> download another thing -> do something again...
Then you can also use javascript waterfall (library or build your own) to make it simple and easy to use. On waterfall you define what should happen when async function is done, one by one.

Using Javascript / JQuery to access an array built from an external XML file

I hope this is not too much of a newbe question but I've been pulling my hair out for a while now so thought I'd give in and ask for my first piece of advice on here.
I'm trying to read an external xml file using javascript / jQuery / ajax and place the retrieved data into an array so that I can then reference it later.
So far I seem to be doing everything right upto the point I put the data into the array but then I'm struggling to to read the data anywhere other than inside the function where I create it. Why am I not able to access the Array from anywhere other than in that function?
Here is my code...
Please help!!
$.ajax({
type: "GET",
url: "data.xml",
dataType: "xml",
success: do_xmlParser
});
function do_xmlParser(xml)
{
var myArray = new Array();
$(xml).find("tag").each(function ()
{
myArray.push($(this).find("innerTag").text());
});
console.log("inside "+myArray); // This outputs the array I am expecting
return myArray; // is this right???
}
console.log("outside: "+myArray); // This does NOT output the array but instead I get "myArray is not defined"
You're defining do_xmlParser as a callback to an asynchronous function (success of the jquery ajax call). Anything you want to happen after the ajax call succeeds has to occur within that callback function, or you have to chain functions from the success callback.
The way you have it now, the actual execution of code will go:
ajax -> file being requested -> console.log ->
file transfer done -> success handler
If you're doing some critical stuff and you want the call be to synchronous, you can supply the
async : false
setting to the ajax call. Then, you should be able to do something like this:
var myArray = [],
do_xmlParser = function (xml)
{
$(xml).find("tag").each(function ()
{
myArray.push($(this).find("innerTag").text());
});
};
$.ajax({
type: "GET",
url: "data.xml",
dataType: "xml",
success: do_xmlParser,
async: false
});
console.log("outside: " + myArray);
The async option doesn't work for cross-domain requests, though.
NOTE
I don't recommend doing this. AJAX calls are supposed to be asynchronous, and I always use the success callback to perform all of the processing on the returned data.
Edit:
Also, if you're into reading... I'd recommend jQuery Pocket Reference and JavaScript: The Definitive Guide (both by David Flanagan).
look close and you will see. You are actually firing up an array that dosen't exist. You have declared myArray inside function. Try do something like this.
console.lod("outside :"+do_xmlParser(xml)); // I think that when you merge a string and an array it will output only string, but I can be wrong.

Categories

Resources