javascript wait for several callback finished - javascript

I have a following javascript program:
function jQueryFunction(url, callback)
{
$.ajax
({
type: "GET",
async: true,
url: url,
dataType: "jsonp",
jsonp: "callback",
jsonpCallback: "tpsHandler",
success: function(json)
{
return callback(json);
}
});
}
var jsonArray = new Array();
for(var i = 0; i < 10; i++)
{
jQueryFunction(url[i], function(json){
jsonArray[i] = json;
});
}
//process jsonArray
However, when I check jsonArray after the for loop, it is null. So my question is that how to store the return value from jQueryFunction to jsonArray in for loop and then process it?
I have tried $.when.apply($,jsonArray).done(function) but still the same, it is null.

A simple way:
function doTheAjax(url, callback) {
return $.ajax({
type: "GET",
async: true,
url: url,
dataType: "jsonp",
jsonp: "callback",
jsonpCallback: "tpsHandler"
});
};
var reqs = [];
for(var i = 0; i < 10; i++) {
reqs.push(doTheAjax(url[i]));
}
// send the array of requests to when, which will fire `done`
// when it's, well, done
$.when.apply($.when, reqs).done(function() {
$.each(arguments, function(data) {
// process the data
});
});
alternatively, make a bunch of requests and put them into jsonArray, but keep
track of how many you're making. When they all complete, you have the array. Create your
own deferred, resolve it yourself when the counter is up, and return the promise.
var getJSON = function(url) {
var dfd = $.Deferred();
var count = 0;
var total = 10;
var jsonArray = [];
for(var i = 0; i < total; i++) {
doTheAjax(url[i]).done(function(json) {
jsonArray.push(json);
count++;
if ( count >= total ) {
dfd.resolve(jsonArray);
}
});
}
return dfd.promise();
};
getJSON().done(function(theCreatedJsonArray) {
// do stuff
});

I'm not sure why the answer to your previous question (using deferreds) didn't work. But the cause of your problem is that you are checking the array before any of the ajax responses arrived. You also have a problem with i referencing the same value on all callbacks.
One simple workaround, if you know how many responses you're expecting:
var arr = [];
for(var i = 0; i < 10; i++){
jQueryFunction(url[i], function(json){
arr.push(json);
if(arr.length == 10) {
// All 10 responses arrived!
// DO STUFF FROM HERE
// e.g., call another function
console.log(arr);
}
});
}

Related

Passing C# function return value to Javascript

what i'm doing is, i'm calling a C# function so it returns the data i will use in Javascript,
However when i read the data from javascript it's always undefined, I debugged the C# function and found out that it actually returns the correct data, so i'm thinking i'm only having trouble receiving it from Javascript.
Here is the c# function i'm calling
[WebMethod]
public static string CommonBus(int StopNo1, int StopNo2)
{
JavaScriptSerializer oSerializer = new JavaScriptSerializer();
LinkedList<int> StopBusNo1 = new LinkedList<int>();
LinkedList<int> StopBusNo2 = new LinkedList<int>();
StopBusNo1 = LookForBuses(StopNo1); //Returns the buses that stop at StopNo1
StopBusNo2 = LookForBuses(StopNo2);
LinkedList<int> CommonBusNos = LookForCommonBuses(StopBusNo1.First, StopBusNo2.First);// Get common buses that stop at both stops
LinkedListNode<int> commonNo = CommonBusNos.First;
LinkedList<Bus> availableBus = new LinkedList<Bus>();
while (commonNo != null)
{
availableBus.AddLast(GetCommonBusIntel(commonNo.Value, StopNo1, StopNo2));
commonNo = commonNo.Next;
}
return oSerializer.Serialize(availableBus);
}
And here is the Javascipt side
function FindTransportation(startStops, endStops) {
for (var i = 0; i < startStops.length; i++) {
for (var x = 0; x < endStops.length; x++) {
availabeTransports.push(PageMethods.CommonBus(startStops[i].StopNo, endStops[x].StopNo)); // Trying to push the returned data into an array
}
}
}
Alright found the answer thank you for your comments.
i edited the FindTransportation function
function FindTransportation(length1, length2) {
for (var i = 0; i < length1; i++) {
for (var x = 0; x < length2; x++) {
GetCommonBuses(i, x);
}
}
}
and i also created the GetCommonBuses function for ajax calls
function GetCommonBuses(index1,index2) {
$.ajax({
type: "POST",
url: "/HomePage.aspx/CommonBus",
data: JSON.stringify({ StopNo1: startWalkableStops[index1].StopNo, StopNo2: endWalkableStops[index2].StopNo }),
contentType: "application/json; charset:utf-8",
dataType: "json",
})
.done(function (res) {
availabeTransports.push(res);
});
}

How to get JSON result from an API call using jQuery(or Javascript) in a non-Ajax way?

I am new to JS an jQuery. And I am trying to build a key-value map from an API call which returns an array of key-value pairs.
[{"key":"191","value":244}, ... , {"key":"920","value":130}]
I came up with this ajax code. But following code will need the map constructed from loadMap. How to change it to non-ajax way that the "followingFunction" runs after loadMap finishes>
var mp = {};
(function loadMap() {
$.ajax({
type: 'GET',
url:'http://localhost:8080/xxx/api?start_date=2014-10-01&end_date=2014-11-01',
dataType: "json",
success: function(arr){
var out = "";
for(i = 0; i<arr.length; i++) {
mp[arr[i].key] = arr[i].value;
}
}
});
}());
//followingFunction which needs the information from mp
You can solve this in two different ways.
1) ExecutefollowingFunctionat the end of your success callback:
var mp = {};
function loadMap() {
$.ajax({
type: 'GET',
url:'http://localhost:8080/xxx/api?start_date=2014-10-01&end_date=2014-11-01',
dataType: "json",
success: function(arr){
var out = "";
for(i = 0; i<arr.length; i++) {
mp[arr[i].key] = arr[i].value;
}
followingFunction();
}
});
};
loadMap();
2) Set the async flag to false (by default this flag is true). This will result in blocking call with synchronous execution:
var mp = {};
function loadMap() {
$.ajax({
type: 'GET',
url:'http://localhost:8080/xxx/api?start_date=2014-10-01&end_date=2014-11-01',
dataType: "json",
async: false,
success: function(arr){
var out = "";
for(i = 0; i<arr.length; i++) {
mp[arr[i].key] = arr[i].value;
}
}
});
};
loadMap();
followingFunction();

Loop through XML files jQuery

I am a bit stuck with the following problem.
I have several XML files tagged by an ID (every XML is id'd by a value). I am now trying to loop through these files and output its contents to HTML.
However it starts the loop before it does the call back
Loop0
Loop1
Loop2
Callback0
Callback1
Callback2
I would need
Loop0
Callback0
Loop1
Callback1
As I need to control the results at some point.
var allContent=["xmlfile1","xmlfile2","xmlfile3","xmlfile4"];
var totalSearch = 0;
var countSearch = 0;
function doSearch() {
var oldContentID = contentID;
for (iSearch=0;iSearch<allContent.length;iSearch++) {
totalSearch = totalSearch + countSearch;
contentID = allContent[iSearch];
defineContent();
getXML();
}
}
function getXML() {
$.ajax({
type: "GET",
url: langFile,
dataType: "xml",
beforeSend: function(){
$('#results-list').empty();
$('#results-list').hide();
$('#loading').addClass('loading');
},
success: function(xml) {
var totalElements;
var intSearch = 0;
totalSearch = totalSearch + countSearch;
countSearch = 0;
var searchText = $('#text').val().toLowerCase();
totalElements = $(xml).find('news').length;
while (intSearch < totalElements) {
oFeed = $(xml).find('news:eq('+intSearch+')');
var headline = oFeed.find('headline').text();
var newsText = oFeed.find('detail').text();
var section = oFeed.find('section').text();
var category = oFeed.attr('category');
var stripEnters = newsText.match(/\r?\n|\r/gi);
if (stripEnters != null) {
for (var s = 0; s < stripEnters.length ; s++ ){
newsText = newsText.replace(stripEnters[s],'');
}
}
var newsText2 = $.htmlClean(newsText, {format:true});
var newsText3 = $(newsText2)
var newsText4 = $(newsText3).text();
var newsText5 = newsText4.replace( /\W/gi, "" );
if (section.toLowerCase() == "news" || section.toLowerCase() == "featured") {
if (headline.toLowerCase().indexOf(searchText) >= 0) {
$('<dt></dt>').html(headline).appendTo('#results-list');
$('<dd></dd>').html(newsText).appendTo('#results-list');
countSearch++;
}//end if
else if (newsText5.toLowerCase().indexOf(searchText) >= 0) {
$('<dt></dt>').html(headline).appendTo('#results-list');
$('<dd></dd>').html(newsText).appendTo('#results-list');
countSearch++;
}
}
intSearch++;
}
}
});
}
At the end of the call backs I need to run the following, however it now executes this function before it finishes all call backs.
function displayResults() {
if (totalSearch == 0)
{
alert("No results found");
$('#loading').removeClass('loading');
$('#main').fadeIn(1000);
}
else {
dynamicFaq();
$('<p></p>').html(totalSearch + ' Results found').prependTo('#results-list');
$('#results-list').fadeIn(1000);
$('#loading').removeClass('loading');
}
}
If I understood you correctly, you want to load 1 xml file, loop, and then start to load the next xml file. If so, here is a little pseudo code:
function doSearch(int xmlFileIterator){
if (xmlFileIterator < allContent.length) {
...
contentID = allContent[xmlFileIterator];
...
getXml(xmlFileIterator);
} else {
//no more xml files left
displayResults();
}
}
function getXml(int xmlFileIterator) {
...
success: function() {
...
doSearch(++xmlFileIterator);
}
}
The first call is doSearch(0) which loads the first xml file. After the file is loaded and the loop is done (in success) you can call the doSearch function again with a higher number (iterator).
I see your AJAX call is Asynchronous. Try using
....
type: "GET",
url: langFile,
async: false,
dataType: "xml",
.....
Maintain a ajax queue so thos ajax call will be done one by one. plus maintain a global variable searchedCount which will maintain how main xml are proccessed.
In complete callback of ajax check for the searchedCount and call displayResults function .
var allContent = ["xmlfile1", "xmlfile2", "xmlfile3", "xmlfile4"];
var totalSearch = 0;
var countSearch = 0;
var searchedCount = 0;
var ajaxQueue = $({});
$.ajaxQueue = function (ajaxOpts) {
// Hold the original complete function.
var oldComplete = ajaxOpts.complete;
// Queue our ajax request.
ajaxQueue.queue(function (next) {
// Create a complete callback to fire the next event in the queue.
ajaxOpts.complete = function () {
// Fire the original complete if it was there.
if (oldComplete) {
oldComplete.apply(this, arguments);
}
// Run the next query in the queue.
next();
};
// Run the query.
$.ajax(ajaxOpts);
});
};
function doSearch() {
var oldContentID = contentID;
searchedCount = 0;
for (iSearch = 0; iSearch < allContent.length; iSearch++) {
totalSearch = totalSearch + countSearch;
contentID = allContent[iSearch];
defineContent();
searchedCount++;
getXML();
}
}
function getXML() {
$.ajaxQueue({
type: "GET",
url: langFile,
dataType: "xml",
beforeSend: function () {
$('#results-list').empty();
$('#results-list').hide();
$('#loading').addClass('loading');
},
success: function (xml) {
//your code
},
complete: function () {
if (searchedCount == allContent.length) {
displayResults()
}
}
});
}

Send back returned response to ajax call

I have a ajax function in index.php which calls on the page thread.php which returns a JSON response(array). I basically want to parse through that array, display it in a particular html format, take the last value of the last row of that array and send it back in the same ajax call previously mentioned. So that ajax is basically a loop.
function returnValue()
{
$.ajax({
async: true,
type: "GET",
url: "thread.php",
data: {lastposted : dateposted},
dataType: "json",
success: function (json) {
if(json) {
{
for (var i = 0, len = json.length; i < len; i++) {
var results = json[i];
var newDiv = $("<div><img src='" + results[0] +"'/>" + results[2] + results[3] + results[4] + results[5] + "</div><br>");
$('#chatContents').append(newDiv);
var dateposted = results[5];
}
}
}
}
});
}
The stored value dateposted needs to be sent as an input when making the ajax call. The default value of dateposted will be 0.
I am not sure if this can be done. I am open to suggestions.
You can make this a lot simpler, you don't need to use the extended GET syntax:
var returnValue = (function() {
var dateposted = 0;
return function() {
$.get("thread.php", { "lastposted": dateposted }, function(result) {
// display your chats
dateposted = result[result.length-1][5];
}, "json");
}
})();
One simple way to your problem is declaring dateposted with a default value outside the function call and use it in the loop to store to store the last value. And have a new Ajax function call. I hope this is want you want.
function returnValue()
{
var dateposted=0;
$.ajax({
async: true,
type: "GET",
url: "thread.php",
data: {lastposted : dateposted},
dataType: "json",
success: function (json) {
if(json) {
{
for (var i = 0, len = json.length; i < len; i++) {
var results = json[i];
var newDiv = $("<div><img src='" + results[0] +"'/>" + results[2] + results[3] + results[4] + results[5] + "</div><br>");
$('#chatContents').append(newDiv);
dateposted = results[5];
}
}
}
}
});
}

Javascript Function Returns Undefined JSON Object (But It's Not Undefined!)

I am trying to return a JSON object from a function using the JSON jQuery plugin (http://code.google.com/p/jquery-json/) but after returning the object from the function, it becomes undefined.
$(document).ready(function() {
var $calendar = $('#calendar');
$calendar.weekCalendar({
...
data : function(start, end, callback) {
var datas = getEventData();
alert(datas); // Undefined???
}
});
If I inspect the object before returning it, it is defined.
function getEventData() {
var dataString = "minDate="+ minDate/1000 + "&maxDate=" + maxDate/1000;
//alert(dataString);return false;
$.ajax({
type: "POST",
url: "busker_ops.php",
data: dataString,
dataType: "json",
success: function(data) {
if(data != null) {
var jsonArray = new Array();
var jsonObj = {};
for(var i = data.length - 1; i >= 0; --i) {
var o = data[i];
var set_id = o.set_id;
var start = o.startOrig;
var end = o.endOrig;
var title = o.title;
var deets = o.deets;
jsonObj =
{
"id":parseInt(set_id),
"start":$("#calendar").weekCalendar("formatDate", new Date(start), "c"),
"end":$("#calendar").weekCalendar("formatDate", new Date(end), "c"),
"title":title,
"body":deets
};
jsonArray[i] = jsonObj;
}
alert($.toJSON(jsonArray)); // Defined!
return ($.toJSON(jsonArray));
} else {
}
}
});
}
Any idea what I'm missing here?
function getEventData() {
function local() {
console.log(42);
return 42;
}
local();
}
Your missing the fact that the outer function returns undefined. And that's why your answer is undefined.
Your also doing asynchronous programming wrong. You want to use callbacks. There are probably 100s of duplicate questions about this exact problem.
Your getEventData() function returns nothing.
You are returning the JSON object from a callback function that's called asynchronously. Your call to $.ajax doesn't return anything, it just begins a background XMLHttpRequest and then immediately returns. When the request completes, it will call the success function if the HTTP request was successful. The success function returns to code internal in $.ajax, not to your function which originally called $.ajax.
I resolved this by using callbacks since AJAX is, after all. Once the data is retrieved it is assigned to a global variable in the callback and the calendar is refreshed using the global variable (datas).
$(document).ready(function() {
// Declare variables
var $calendar = $('#calendar');
datas = "";
set = 0;
// Retrieves event data
var events = {
getEvents : function(callback) {
var dataString = "minDate="+ minDate/1000 + "&maxDate=" + maxDate/1000;
$.ajax({
type: "POST",
url: "busker_ops.php",
data: dataString,
dataType: "json",
success: function(data) {
if(data != null) {
var jsonArray = new Array();
var jsonObj = {};
for(var i = data.length - 1; i >= 0; --i) {
var o = data[i];
var set_id = o.set_id;
var start = o.startOrig;
var end = o.endOrig;
var title = o.title;
var deets = o.deets;
jsonObj =
{
"id":parseInt(set_id),
"start":$("#calendar").weekCalendar("formatDate", new Date(start), "c"),
"end":$("#calendar").weekCalendar("formatDate", new Date(end), "c"),
"title":title,
"body":deets
};
jsonArray[i] = jsonObj;
}
//alert($.toJSON(jsonArray));
callback.call(this,jsonArray);
} else {
}
}
});
}
}
$calendar.weekCalendar({
data : function(start, end, callback) {
if(set == 1) {
callback(datas);
//alert(datas.events);
}
}
});
// Go get the event data
events.getEvents(function(evented) {
displayMessage("Retrieving the Lineup.");
datas = {
options : {},
events : evented
};
set = 1;
$calendar.weekCalendar("refresh");
});
});

Categories

Resources