Call Javascript callback in a loop - javascript

I'm a javascript newbie and has been given a problem to solve so i really need your help.
The problem is this:
I have a loop of companies list. For each company I need to make a ajax call like below.
My problem is that I want to stay in the loop and just get the value that the ajax call return so I can use that value there. Now I get the return value to the getData method. How can I solve this?
for (var j = 0; j < companiesToList.length; j = j + 1) {
getCompanyData(companiesToList[j].id, numberArray, function(data){
getData(data)
}
}
var getCompanyData = function(companyid, numbers, callback) {
var baseUrl = '../data/financial/company/';
baseUrl += companyid + '/';
numbers = numbers.distinct();
baseUrl += numbers.join(',');
tiger.ajax.core.getJSON(baseUrl, null, function(data) {
callback(data.financial);
});
};

A good way to solve this is with promises, using a library like kriskowal's Q (or any other interface that implements the promise API):
for (var j = 0; j < companiesToList.length; j = j + 1) {
getCompanyData(companiesToList[j].id, numberArray, function(data){
getData(data).then(function(result) {
// do something with result asynchronously
}
}
}
var getCompanyData = function(companyid, numbers, callback) {
// create a deferred object to return
var deferred = Q.defer();
var baseUrl = '../data/financial/company/';
baseUrl += companyid + '/';
numbers = numbers.distinct();
baseUrl += numbers.join(',');
tiger.ajax.core.getJSON(baseUrl, null, function(data) {
// resolve the promise with the retrieved data
deferred.resolve(data.financial);
});
// return the unresolved promise immediately
return deferred.promise;
};
Whether the above will work out of the box for your situation depends on what exactly you need to do inside the loop after the results come back, since if you want to be picky you aren't actually staying inside the loop, but using then as a callback (if you will) to execute code after the result is retrieved. That being said, the above pattern works well in a lot of situations like this. I can edit my answer if you provide more information about what you need to do with the data.

Related

Iterate through dependent getjson() calls

I'm trying to perform the following actions at a high level:
Make an API call to generate an array of cardIDs for a Trello board
Iterate and make an API call for each cardID, pull some action (history) data for each card and store that in the action_tableData table
Once complete, append action_tableData to the table object
The way I understand things is that I need to perform a getJSON call, let that finish and then perform another getJSON on top of that. I've looked around and understand the $.when() function might help, but I can't seem to even remotely make that work.
I think there could be an issue when the getJSON returns an undefined object, but I'm not sure how to skip those. Any help would be most appreciated!
cardIDapiCall = "https://api.trello.com/1/boards/" + boardID + "/cards?fields=id&key=" + appKey + "&token=" + tokenKey;
$.getJSON(cardIDapiCall, function(cardID) {
var cardID_tableData = [];
// Iterate over the JSON object
for (var i = 0, len = cardID.length; i < len; i++) {
cardID_tableData.push({
"card_id": cardID[i].id,
});
}
//get action data
for (var j = 1, len = cardID_tableData.length; j < len; j++) {
//this alert works
alert("card id: " + cardID_tableData[j].card_id);
var actionapiCall = "https://api.trello.com/1/cards/" + cardID_tableData[j].card_id + "/actions?key=" + appKey + "&token=" + tokenKey;
//why isn't this getting called???
$.getJSON(actionapiCall, function() {
//this alert doesn't work
alert("action call successful");
});
var action_tableData = [];
action_tableData.push({
"action_id": action[j].id,
"action_type": action[j].type,
})
table.appendRows(action_tableData);
doneCallback();
}
});

Retrieving a variable from within a function

I am attempting to pull information from the League of Legends API.
To simplify what I am doing, I am attempting to pull information about a user and their previous matches. The problem that I run into is that when I parse a JSON request, it returns a champion ID rather than their name (Ex: 412 rather than "Thresh").
The only solution I can see for this would be to make another JSON request and parse that data for the champion name. Currently what I have looks like this.
$.getJSON(championMasteryPHP, function (json) {
for (var i = 0; i < 20; i++) {
var champID = json[i].championId;
var championInfo = "http://example.com/champInfo.php?summonerid=" + champID;
$.getJSON(championInfo, function (json2) {
var champName = json2.name;
});
$('#champ').append("<li>"+champID+" - "+champName+"</li>")
}
});
I'm unable to access the champName variable due to it being nested within the second JSON function.
Is there a better way to do this?
$.getJSON(championMasteryPHP, function (json) {
for (var i = 0; i < 20; i++) {
var champID = json[i].championId;
var championInfo = "http://example.com/champInfo.php?summonerid=" + champID;
$.getJSON(championInfo, function (json2) {
var champName = json2.name;
$('#champ').append("<li>"+champID+" - "+champName+"</li>")
});
}
});
Just put it inside the second json request since you need to wait till that request is done anyway.
You should put the append statement in the callback because getJSON is an asynchronous method (does mean the Request is running in the background, and calls your function back when it got a response), so you should wait for the response first then you can append it to #champ :
$.getJSON(championMasteryPHP, function (json) {
for (var i = 0; i < 20; i++) {
var champID = json[i].championId;
var championInfo = "http://example.com/champInfo.php?summonerid=" + champID;
$.getJSON(championInfo, function (json2) {
var champName = json.name;
$('#champ').append("<li>"+champID+" - "+champName+"</li>")
});
}
});
Hope this helps.

Async loading files with Angular into an object array and keeping their order

I'm not loading scripts, I'm reading XML files into an array of objects.
My first [dumb] attempt was something like:
for (var i = 1; i < n; i++) {
var filePath = "xml/chapter_"+i+".xml";
$http.get( filePath ).success(function (data) {
$scope.chaptersData.push (data._chapter);
});
}
I quickly figured out this was no good, because the array will be filled in the order the files finished loading, not when they started (a race condition) and the smaller ones will finish first. I can't use the value of 'i' because of course it gets to 'n' long before any of the loading finishes.
After that I thought success(function (data, i) { would work, but it didn't. I'm out of simple ideas, and before I come up with some kind of Rube Goldberg kludge I thought I would ask the wisdom of the Internets if there is a 'right' way to do this.
You can pass i into a function which performs the request.
for (var i = 1; i < n; i++) {
getFile(i);
}
function getFile(index){
var filePath = "xml/chapter_" + index + ".xml";
$http.get( filePath ).success(function (data) {
$scope.chaptersData[index] = data._chapter;
});
}
Within the getFile function, the value of the parameter index will not change as i changes in the outer function. So it will still be at its initial value when the success function executes and can be used for populating the array.
Just get data as an object like
{
order: [] // just your chapter id or whatever identifier value in desired order
data: // whatever you're getting now
}
In your .success (which is btw depreciated and you should use .then() instead) just do
orderedChapters = [];
for (var i = 0; i < order.length; i++) {
for (var j = 0; j < data.length; i++) {
if (order[i] == data[j].id) {
orderedChapters.push(data[j]);
}
}
}

I cant read params value from req.params in restify (node JS)

I am trying to read the parameters value from req.params but in a different way (I am trying to make an API in RESTIFY).
First I read the keys that are available in req.params, like;
var requestData = Object.keys(request.params);
And than I loop through each key and try to fetch its value. below is the code;
for(i = 1; i < requestData.length; i++) {
keyValue = requestData[i];
console.log(request.params.keyValue);
}
But the output shows me UNDEFINED.
Reason: I am trying to read the parameters this way because, then, I do not need to know the name of each parameter.
Below is the complete code:
var restify = require('restify');
var assert = require('assert');
var server = restify.createServer();
var client = restify.createStringClient({
url: 'http://example.com'
});
function onRequest(request, response, next)
{
console.log(request.params);
var requestData = Object.keys(request.params);
var customJsonString = '';
var keyValue = '';
for(i = 1; i < requestData.length; i++) {
keyValue = requestData[i];
console.log(request.params.keyValue);
customJsonString += "" + requestData[i] + " : " + requestData[i] + ", ";
}
console.log(customJsonString);
}
function start()
{
server.use(restify.fullResponse()).use(restify.bodyParser());
server.get(/^\/(.*)/, onRequest);
server.post(/^\/(.*)/, onRequest);
server.listen(8888);
console.log("Server has started.");
}
exports.start = start;
I will really appreciate any help regarding this issue.
Try this instead:
console.log(request.params[keyValue]);
request.params.keyValue means Give me the value of the property keyValue, whereas the code above means Give me the value of the property whose name is stored in the variable keyValue.
Also, are you sure you want to start with i = 1? Javascript-arrays are 0-based, so I think you want i = 0 instead.
It could help if you can give us the URL you are testing right now as well as the console output your get.
However, please note that arrays in Javascript have 0 based index and your loop should look like this:
for(var i = 0; i < requestData.length; i++) {
}
To loop through the properties of an object, you should probably use for..in anyway:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
I don't know if that will solve your problem but it's a start.

How does jQuery do async:false in its $.ajax method?

I have a similar question here, but I thought I'd ask it a different way to cast a wider net. I haven't come across a workable solution yet (that I know of).
I'd like for XCode to issue a JavaScript command and get a return value back from an executeSql callback.
From the research that I've been reading, I can't issue a synchronous executeSql command. The closest I came was trying to Spin Lock until I got the callback. But that hasn't worked yet either. Maybe my spinning isn't giving the callback chance to come back (See code below).
Q: How can jQuery have an async=false argument when it comes to Ajax? Is there something different about XHR than there is about the executeSql command?
Here is my proof-of-concept so far: (Please don't laugh)
// First define any dom elements that are referenced more than once.
var dom = {};
dom.TestID = $('#TestID'); // <input id="TestID">
dom.msg = $('#msg'); // <div id="msg"></div>
window.dbo = openDatabase('POC','1.0','Proof-Of-Concept', 1024*1024); // 1MB
!function($, window, undefined) {
var Variables = {}; // Variables that are to be passed from one function to another.
Variables.Ready = new $.Deferred();
Variables.DropTableDeferred = new $.Deferred();
Variables.CreateTableDeferred = new $.Deferred();
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'drop table Test;',
[],
Variables.DropTableDeferred.resolve()
// ,WebSqlError
);
});
$.when(Variables.DropTableDeferred).done(function() {
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'CREATE TABLE IF NOT EXISTS Test'
+ '(TestID Integer NOT NULL PRIMARY KEY'
+ ',TestSort Int'
+ ');',
[],
Variables.CreateTableDeferred.resolve(),
WebSqlError
);
});
});
$.when(Variables.CreateTableDeferred).done(function() {
for (var i=0;i < 10;i++) {
myFunction(i);
};
Variables.Ready.resolve();
function myFunction(i) {
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'INSERT INTO Test(TestID,TestSort) VALUES(?,?)',
[
i
,i+100000
]
,function() {}
,WebSqlError
)
});
};
});
$.when(Variables.Ready).done(function() {
$('#Save').removeAttr('disabled');
});
}(jQuery, window);
!function($, window, undefined) {
var Variables = {};
$(document).on('click','#Save',function() {
var local = {};
local.result = barcode.Scan(dom.TestID.val());
console.log(local.result);
});
var mySuccess = function(transaction, argument) {
var local = {};
for (local.i=0; local.i < argument.rows.length; local.i++) {
local.qry = argument.rows.item(local.i);
Variables.result = local.qry.TestSort;
}
Variables.Return = true;
};
var myError = function(transaction, argument) {
dom.msg.text(argument.message);
Variables.result = '';
Variables.Return = true;
}
var barcode = {};
barcode.Scan = function(argument) {
var local = {};
Variables.result = '';
Variables.Return = false;
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'SELECT * FROM Test WHERE TestID=?'
,[argument]
,mySuccess
,myError
)
});
for (local.I = 0;local.I < 3; local.I++) { // Try a bunch of times.
if (Variables.Return) break; // Gets set in mySuccess and myError
SpinLock(250);
}
return Variables.result;
}
var SpinLock = function(milliseconds) {
var local = {};
local.StartTime = Date.now();
do {
} while (Date.now() < local.StartTime + milliseconds);
}
function WebSqlError(tx,result) {
if (dom.msg.text()) {
dom.msg.append('<br>');
}
dom.msg.append(result.message);
}
}(jQuery, window);
Is there something different about XHR than there is about the executeSql command?
Kind of.
How can jQuery have an async=false argument when it comes to Ajax?
Ajax, or rather XMLHttpRequest, isn't strictly limited to being asynchronous -- though, as the original acronym suggested, it is preferred.
jQuery.ajax()'s async option is tied to the boolean async argument of xhr.open():
void open(
DOMString method,
DOMString url,
optional boolean async, // <---
optional DOMString user,
optional DOMString password
);
The Web SQL Database spec does also define a Synchronous database API. However, it's only available to implementations of the WorkerUtils interface, defined primarily for Web Workers:
window.dbo = openDatabaseSync('POC','1.0','Proof-Of-Concept', 1024*1024);
var results;
window.dbo.transaction(function (trans) {
results = trans.executeSql('...');
});
If the environment running the script hasn't implemented this interface, then you're stuck with the asynchronous API and returning the result will not be feasible. You can't force blocking/waiting of asynchronous tasks for the reason you suspected:
Maybe my spinning isn't giving the callback chance to come back (See code below).

Categories