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

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.

Related

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 AJAX inside another AJAX call. Sync and finished issues

I get a list of users with an AJAX call, but within the AJAX I call another AJAX to get some information that I could not get with the first AJAX call.
This is basically the structure I'm using, I've removed some unneccesary code that would just clutter, it is possible that there is some syntax errors here and there.
But the code basically works but there are some issues.
function doAJAX(){
$(".loading").show();
$("#table").hide();
$.ajax({
type: "POST",
url: "#Url.Action("Action", "Controller")",
data: { variable: varVariable},
dataType: "json",
success: function (data) {
$.each(data, function (index, value) {
$.ajax({
type: "POST",
url: "#Url.Action("Action", "Controller")",
data: { variable: value.id},
success: function (data2) {
$.each(data2, function (index2, value2) {
$("#tableBody").append("<tr><td>" + value.test +"</td><td>" + value2.test +"</td></tr>");
});
}
});
});
}
});
}
I hide my table at the start, when the AJAX is complete I want to show it again. Where exactly should I place it? Even if I place it at the end of the first AJAX success function it does not work because it gets executed while the other AJAX is still running.
For some reason my list ends up in an odd order everytime the AJAX runs, my list is sorted by alphabetical order yet with this AJAX it ends up random everytime, sometimes the user Adam is at the start, sometimes in the middle and so on. The list itself is fine and in correct order
I do a lot of mathematics that is probably slowing down the second AJAX call which is probably why it ends up in a weird order
Both of these issues are happening because the two AJAXs aren't running "together" but individually, is there a way to make them sync with each other and is there a good way to be sure that the AJAX is completed and now I can show my table?
Sending ajax request inside a loop doesn't seem like a good idea. Why won't you send one ajax request with array of id's as a data, inside your serverside script just get "WHERE id IN (id_list)" array of user records and return them as json-encoded object, and then output it inside a double loop, first for <tr>, second for a list of fields.
I'm sorry i can't provide code, as i don't know what is being returned from your requests to server.

Wait for data from external API

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.

Load .txt file using JQuery or Ajax

How can I fix the script below so that it will work EVERY TIME! Sometimes it works and sometimes it doesn't. Pro JQuery explains what causes this, but it doesn't talk about how to fix it. I am almost positive it has to do with the ajax ready state but I have no clue how to write it. The web shows about 99 different ways to write ajax and JQuery, its a bit overwhelming.
My goal is to create an HTML shell that can be filled with text from server based text files. For example: Let's say there is a text file on the server named AG and its contents is PF: PF-01, PF-02, PF-03, etc.. I want to pull this information and populate the HTML DOM before it is seen by the user. A was ##!#$*& golden with PHP, then found out my host has fopen() shut off. So here I am.
Thanks for you help.
JS - plantSeed.js
var pageExecute = {
fileContents:"Null",
pagePrefix:"Null",
slides:"Null",
init:function () {
$.ajax({
url: "./seeds/Ag.txt",
success: function (data){
pageExecute.fileContents = data;
}
});
}
};
HTML - HEAD
<script type="text/javascript">
pageExecute.init();
</script>
HTML - BODY
<script type="text/javascript"> alert(pageExecute.fileContents); </script>
Try this:
var pageExecute = {
fileContents:"Null",
pagePrefix:"Null",
slides:"Null",
init: function () {
$.ajax({
url: "./seeds/Ag.txt",
async: false,
success: function (data){
pageExecute.fileContents = data;
}
});
}
};
Try this:
HTML:
<div id="target"></div>
JavaScript:
$(function(){
$( "#target" ).load( "pathToYourFile" );
});
In my example, the div will be filled with the file contents. Take a look at jQuery .load() function.
The "pathToYourFile" cand be any resource that contains the data you want to be loaded. Take a look at the load method documentation for more information about how to use it.
Edit: Other examples to get the value to be manipulated
Using $.get() function:
$(function(){
$.get( "pathToYourFile", function( data ) {
var resourceContent = data; // can be a global variable too...
// process the content...
});
});
Using $.ajax() function:
$(function(){
$.ajax({
url: "pathToYourFile",
async: false, // asynchronous request? (synchronous requests are discouraged...)
cache: false, // with this, you can force the browser to not make cache of the retrieved data
dataType: "text", // jQuery will infer this, but you can set explicitly
success: function( data, textStatus, jqXHR ) {
var resourceContent = data; // can be a global variable too...
// process the content...
}
});
});
It is important to note that:
$(function(){
// code...
});
Is the same as:
$(document).ready(function(){
// code
});
And normally you need to use this syntax, since you would want that the DOM is ready to execute your JavaScript code.
Here's your issue:
You've got a script tag in the body, which is asking for the AJAX data.
Even if you were asking it to write the data to your shell, and not just spout it...
...that's your #1 issue.
Here's why:
AJAX is asynchronous.
Okay, we know that already, but what does that mean?
Well, it means that it's going to go to the server and ask for the file.
The server is going to go looking, and send it back. Then your computer is going to download the contents. When the contents are 100% downloaded, they'll be available to use.
...thing is...
Your program isn't waiting for that to happen.
It's telling the server to take its time, and in the meantime it's going to keep doing what it's doing, and it's not going to think about the contents again, until it gets a call from the server.
Well, browsers are really freakin' fast when it comes to rendering HTML.
Servers are really freakin' fast at serving static (plain-text/img/css/js) files, too.
So now you're in a race.
Which will happen first?
Will the server call back with the text, or will the browser hit the script tag that asks for the file contents?
Whichever one wins on that refresh is the one that will happen.
So how do you get around that?
Callbacks.
Callbacks are a different way of thinking.
In JavaScript, you perform a callback by giving the AJAX call a function to use, when the download is complete.
It'd be like calling somebody from a work-line, and saying: dial THIS extension to reach me, when you have an answer for me.
In jQuery, you'll use a parameter called "success" in the AJAX call.
Make success : function (data) { doSomething(data); } a part of that object that you're passing into the AJAX call.
When the file downloads, as soon as it downloads, jQuery will pass the results into the success function you gave it, which will do whatever it's made to do, or call whatever functions it was made to call.
Give it a try. It sure beats racing to see which downloads first.
I recommend not to use url: "./seeds/Ag.txt",, to target a file directly. Instead, use a server side script llike PHP to open the file and return the data, either in plane format or in JSON format.
You may find a tutorial to open files here: http://www.tizag.com/phpT/fileread.php

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