AJAX - Wait for data to append before looping next - javascript

I am creating a drop down list in JavaScript, I am loading the data via Ajax and JSON, at the moment my code loops through a set of departments and runs into the ajax call in each iteration.
My problem is that my data seems to be appending in a random order, its likely that its loading in the order of whichever loads quickest.
I want to be able to loop through my Ajax call and append the data in the order that I declare (for each department).
is this something that can be done?
Here is my code:
//-- Ajax --
var departments = ['Accounts', 'Commercial', 'Installation', 'Production', 'Sales'];
var i;
for (i = 0; i < departments.length; i++) {
$.ajax({
type: "POST",
url: "Default.aspx/EmployeesDropDown",
data: '{X: "' + departments[i] + '"}',
contentType: "application/json; charset=utf-8",
dataType: "text json",
async: true,
success: createdropdown,
failure: function () {
alert("FAIL!");
}
});
}
//-- Creates dropdown --
function createdropdown(data) {
...appends all the data to my drop down list...
}
Any help or advice is appreciated, thank you in advance.
EDIT: This question is different from the related ones because I need to be able to loop through the string array, rather than just iterating based on numbers.

If you want to load the departments in the order they appear in the departments array you could load them one by one, waiting for each ajax request to finish until you start the next request.
Here is an example:
var departments = ['Accounts', 'Commercial', 'Installation', 'Production', 'Sales'];
var i = 0;
function reqDep(department) {
/*
Since i can't use ajax here let's use a promise.
*/
var p = new Promise(function(res, rej) {
setTimeout(function() {
res(department)
}, 1000)
})
return p;
// This is what you would actually do.
/*
var data = '{X: "' + department + '"}'
return $.ajax({
type: "POST",
url: "Default.aspx/EmployeesDropDown",
data: data,
contentType: "application/json; charset=utf-8",
dataType: "text json",
});
*/
}
function initDepartments(index) {
reqDep(departments[index])
// Here you would use `.done(function(data...`
// I am using `.then(function(data...`
// because of the promise.
.then(function(data) {
console.log(data)
if(i < departments.length) {
initDepartments(i)
}
})
i++;
};
initDepartments(i)

Related

How to handle an ajax request that uses a callback function that has an ajax request itself?

My main issue is that buildItem(data) returns 'undefined'. I've gone through some links on stackoverflow about how to do callback functions but I think that it's getting a bit messy since I'm going through multiple functions here.
I have a list that I'm appending to in this ajax call.
$.ajax({
dataType: "json,
url: "/retrieveTeamView.do?managerEmail=${email}",
cache: false,
success: function (data, status) {
$('#nestable ol').append(buildItem(data));
});
I defined buildItem() as such:
function buildItem(item) {
getTotalCost(item, function(totalCost) {
html += "<span>" + totalCost + "</span>";
return html;
}
}
So all buildItem does is it takes the data and passes it into getTotalCost.
Here my getTotalCost() function should take the item, as it has an attribute "email" that I need for the url, and it should do a loop through the data retrieved from the ajax call to return a totalCost.
function getTotalCost(item, callback) {
$.ajax({
dataType: "json",
url: "/retrieveUserUsage.do?email=" + item.email,
success: function(data) {
var totalCost = 0;
for (var i = 0; i < data.length; i++) {
totalCost += parseFloat(data[i].cost);
}
callback(totalCost);
}
});
}
My understanding is that callback(totalCost) returns back to buildItem() and returns the total cost successfully. From what I understand, doing alert(html) gives me a correct output in the alert dialog, but it is not successfully appended in the ajax function. Am I doing something wrong?
Note: I deleted chunks of details to keep the idea but to still keep the code secretive, so sorry if some parts may not seem like they're used.
I am thinking that the issue is related to the fact that AJAX calls are asynchronous. Therefore, it may be trying to update the DOM before everything is returned.
Therefore you need to nest the calls.
you could try something like this:
$.ajax({
dataType: "json,
url: "/retrieveTeamView.do?managerEmail=${email}",
cache: false,
success: function (data, status) {
$.ajax({
dataType: "json",
url: "/retrieveUserUsage.do?email=" + data.email,
success: function(data) {
var totalCost = 0;
for (var i = 0; i < data.length; i++) {
totalCost += parseFloat(data[i].cost);
}
$('#nestable ol').append("<span>" + totalCost + "</span>");
}
});
}
});

Ajax Pagination with jQuery

I need to retrieve data from an api that has a limit on the number of results being returned.
Using the total number of results found, I'm able to make additional additional ajax calls until all data is retrieved. However, I need sort all the data alphabetically before displaying it on the page.
How can I access the data within the array after ALL ajax calls have been successfully made?
Here is what I have so far:
var mydata = [];
function loadPosts() {
var api = 'http://someurl.com';
$.ajax({
url: api,
dataType: 'jsonp',
data: {
rows: 1,
},
success: function(data) {
totalNumberOfRecords = data.numFound;
for (var start = 0; start < totalNumberOfRecords; start += rows) {
$.ajax({
url: api,
dataType: 'jsonp',
data: {
'rows': rows,
'start': start,
},
success: function(data) {
$.each(data.namesList, function(index, item) {
mydata.push(item.firstName);
});
},
});
}
},
});
}
console.log(mydata);
This is an instant-noodle solution.
var numOfAjax = 0;
var numOfResolvedAjax = 0;
for (var start = 0; start < totalNumberOfRecords; start += rows) {
numOfAjax++;
$.ajax({
url: api,
dataType: 'jsonp',
data: {
'rows': rows,
'start': start,
},
success: function(data) {
$.each(data.namesList, function(index, item) {
mydata.push(item.firstName);
});
numOfResolvedAjax++;
// Check if all ajax request has been responded to sort the result.
if (numOfResolvedAjax === numOfAjax) {
sortMyData(myData);
}
},
});
}
For a perfect solution, please check in async library with a lot of functions which can help you. E.g: async.parallel may be what you need.
Honestly, if it were me with this API limit issue, I'd use the server to talk to the API ever-so-often to capture all the data into my own system - beit MySQL or Redis or whatever. Then I would use my front-end JS however I wanted without limmits

Fetching Data From Multiple Facebook API's then Adding Together

JQuery Snippet
// THE FOUR URL'S TO ADD THE TOTAL SHARES
var Gal_All = "Link One";
var Gal_S_1 = "Link Two";
var Gal_S_2 = "Link Three";
var Gal_S_3 = "Link Four";
$.ajax({
type: 'GET',
url: 'https://graph.facebook.com/' + Gal_All,
success: function(data) {
showCount(data);
}
});
var fbshares;
var fbcomments;
function showCount(responseText) {
var json = responseText;
fbshares = json.shares;
fbcomments = json.comments;
$('#fb-share-count').html(fbshares);
if (fbcomments) {
$('#TotalComments').html(fbcomments + ' comments');
}
showTotal();
}
function showTotal() {
if (!tweets) {
tweets = 0
}
if (!fbshares) {
fbshares = 0
}
if (tweets !== undefined && fbshares !== undefined)
$('#total-share-count').html(tweets + fbshares);
}
For fetching data from one Facebook API I have achieved however my gallery is split up into four pages (Gal_All = all images and Gal_S_1, Gal_S_2, Gal_S_3 = categorized)
Alike I have achieved with my Twitter counter adding for all four pages, I would like to do for Facebook so it is not showing the shares for that page, but all four of the pages.
Please Note: Comments fetch only needs to be from Gal_All
First of all, you can request API data for multiple objects using
/?ids=http://example.com/1,http://example.com/2,http://example.com/3
Now since you want comments as well for your 4th URL, that still needs an extra API request (unless you want to fetch comments for the other three as well, just to throw them away, but that would not make much sense) – but you could use a batch request to at least get those two different API calls done with one single HTTP request. After all, the HTTP request is what takes most of the time in making a request to the API, so if speed is the factor you put the most emphasis on (and why wouldn’t you, users don’t like to be kept waiting), I think this is the best way to go. (Using a promise might be fine from a pure “aesthetic” point of view, but it doesn’t change the fact that multiple HTTP requests are quite slow.)
Use a promise:
var count = 0;
$.when(
$.ajax({
type: 'GET',
url: 'https://graph.facebook.com/' + Gal_All,
success: function(data) {
count += data;
}
});
$.ajax({
type: 'GET',
url: 'https://graph.facebook.com/' + Gal_S_1,
success: function(data) {
count += data;
}
});
$.ajax({
type: 'GET',
url: 'https://graph.facebook.com/' + Gal_S_2,
success: function(data) {
count += data;
}
});
$.ajax({
type: 'GET',
url: 'https://graph.facebook.com/' + Gal_S_3,
success: function(data) {
count += data;
}
});
).then(function() {
showCount();
});

Use of async on successive AJAX calls

Question here about use of successive AJAX calls and async. Its a bit messed here because of how the data is set up. I need to return listings, but the sever only returns 10 per query, and the only way to determine the total number of listings is a separate query with the boolean returnTotal as true instead of false. This returns the number of listings only, and not the listing results themselves. However, if I run the calls synchronously, the variable startItem (which increments on each loop to load data starting at the next block of listings) doesn't seem to populate before the next call finishes, and results get duplicated. Any way to avoid running both as async? Apologies if my code is batshit ridiculous, as I'm relatively new to jquery.
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem=0&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=true",
dataType: "html",
async: false,
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
$(this).find('total').each(function(){
totalList = $(this).text();
totalList = parseInt(totalList);
totalPages = totalList/10;
});
});
},
});
for (i = 0; i < totalPages; i++){
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
startItem = startItem + 10;
popResults();
},
});
}
The problem here is that you do not increment startItem until you receive a response. Your code is probably making multiple requests with startItem === 1 before the first response is even received, and so you will get some really weird behavior (probably will get duplicate responses, and you will only get the first few pages of data).
Avoid using synchronous calls because they will tie up other resources (like javascript).
In this case if you want to insure that you get the data in order, you can make it a serial chain of AJAX calls.
To get serial behavior and enjoy the benefits of AJAX, instead of using a loop make your callback function do the next AJAX request after incrementing startItem.
This is easier if you organize your code into functions. To wit:
function GetData()
{
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: GetData_Callback
});
}
function GetData_Callback(data)
{
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
startItem += 10; // increment startItem
popResults();
if (startItem / 10 < totalPages)
{
GetData(); // get next "page" of data
}
}
var startItem = 1; // global variable will be mutated by GetData_Callback
GetData(); // get first "page" of data
To do this in parallel typically requires management of the parallel responses (you can use semaphores, etc.). For example (psuedo code) you could do something like this:
var pages = [];
var totalPages = GetTotalPages(); // request via ajax like you mentioned (function not shown)
var pagesLoaded = 0;
for(var i = 0; i < totalPages; i++)
{
GetData(pageIdx);
}
function GetData(pageIdx)
{
$.ajax({ ..., success: function(data){GetData_Callback(pageIdx,data);}});
}
function GetData_Callback(pageIdx, data)
{
pages[pageIdx] = data; // assign this specific page of data
pagesLoaded++;
if (pagesLoaded === totalPages)
{
// fully loaded; trigger event or call function to render, etc.
}
}
Do you just mean without the async: false?
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem=0&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=true",
dataType: "html",
success: function(data) {
console.log('test1'); // first response ok
data=convert(data);
$(data).find('Listing').each(function(){
$(this).find('total').each(function(){
totalList = $(this).text();
totalList = parseInt(totalList);
totalPages = totalList/10;
});
});
var startItem=0;
console.log(totalPages); // total page should be equal too "loop" logged
for (i = 0; i < totalPages; i++){
console.log('loop'); // enter the loop
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: function(data) {
console.log('test2'); // number of test 2 = nb of loop = totalPages
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
startItem = startItem + 10;
popResults();
},
});
}
},
});
The problem here is that you do not increment startItem until you receive a response. Your code is probably making multiple requests with startItem === 1 before the first response is even received, and so you will get some really weird behavior (probably will get duplicate responses, and you will only get the first few pages of data).
Try this instead. It still uses your loop but it increments startItem in the loop before the next request is made to insure that all pages of data are requested.
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem=0&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=true",
dataType: "html",
async: false,
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
$(this).find('total').each(function(){
totalList = $(this).text();
totalList = parseInt(totalList);
totalPages = totalList/10;
});
});
},
});
var startItem = 1;
for (i = 0; i < totalPages; i++){
$.ajax({
type: "POST",
url:server url here,
data:"creativeID=test&CompanyId=BHSR&StartItem="+startItem+"&streetlocation="+choiceTown+"&Location="+sectCode+"&PriceMin="+choiceMin+"&PriceMax="+choiceMax+"&ListingType="+checkRB+"&OpenHouse=false&NewDev=false&AuthenticationId=id&ReturnTotal=false",
dataType: "html",
success: function(data) {
data=convert(data);
$(data).find('Listing').each(function(){
results_xml.push($(this));
});
result_index=0;
result_image_counter=1;
popResults();
},
});
// increment start item BEFORE the next request, not in the response
startItem += 10; // now the next request will be for 11, 21, 31, 41, etc...
}
You may want to get familiar with your javascript debugger to see the behavior for yourself.

Using two different ajax call

I have two different ajax calls . First one connects to one method of a web service . if it gets any null value for a specific field then it should call the other method from same web service . Here are the codes ..
$.ajax({
url: "webservices/ProdMonitorService.asmx/GetEstTimePrelimFinalCur",
data: "{'myactivity':'" + myactivity + "'}",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
async: true,
success: function (data) {
var obj = jQuery.parseJSON(data.d);
for (var i = 0; i <= obj.length - 1; i++) {
var dur_time_formated = '';
var mytimedur = obj[i].time_duration;
if (mytimedur != null) {
dur_time_formated = mytimedur.replace('.000000', '');
}
else {
//only one time check for this
$.ajax({
url: "webservices/ProdMonitorService.asmx/GetEstTimePrelimFinalCurTotalProcessing",
data: "{'myactivity':'" + myactivity + "'}",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
async: true,
success: function (data2) {
var obj2 = jQuery.parseJSON(data2.d);
dur_time_formated = obj2[0].total_processtime.replace('.000000', '');
}, error: function (result) {
//alert("Error: Please contact administrator for help: " + result.responseText);
}
});
}
For the first ajax call , it gets obj[0]......obj[7] but let say obj[0].time_duration comes null then it should go to second ajax call ,but even method "GetEstTimePrelimFinalCurTotalProcessing" returns some result , dur_time_formated varialbe comes null;, it is not even go thru second ajax call completely after first one.
Should use done function after first one is completed ?
You should try "async: false" instead of "async: true" here. This will work in your case.
bear in mind that ajax call is async. it means that dur_time_formated will be set later after your for-loop. so to solve the problem you can use any array variable outside your loop or sync ajax request

Categories

Resources