Retrieving a variable from within a function - javascript

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.

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();
}
});

Using response from one API call to do another API Call

I'm using AngularJS to build a site where one of the functions is to present Billboard(it's a music chart) listings for a specified date.
I want to present the songs in order, together with an image of the song.
First I'm calling this API:
http://billboard.modulo.site/
where I give a date and get a response of the top 10 songs for that date and data about each song.
The response from the Billboard API also includes a spotify id and I want to use that ID and call the Spotify Web API to get an image of that song, to complement the information I present about each song.
This is how it looks like in my controller:
var spotifyID = [];
$scope.spotifyImg = [];
musicService.getBillboard($scope.date).then(function(data){ //Response is top 10 songs for given date
$scope.status = "";
$scope.songlist = data;
for (var i = 0; i < data.length; i++) {
spotifyID[i] = data[i].spotify_id; //data[i].spotify_id returns the ID of the track, as given by the billboard API
}
$scope.getImages();
});
$scope.getImages = function() {
for (var i = 0; i < spotifyID.length; i++) {
if(spotifyID[i] !== null) {
musicService.getSpotify(spotifyID[i]).then(function(data){
$scope.spotifyImg[i] = data.album.images[0].url; //returns the appropriate image from the Spotify Web API
});
}
}
console.log($scope.spotifyImg);
}
And in my view it would look something like this:
<div ng-repeat = "song in songlist">
<div>{{ song.rank }}</div>
<div>
<img ng-src=" {{ spotifyImg[$index] }}"/>
</div>
</div>
However, it does not work.
When I'm checking the $scope.spotifyImg array in the console, it is of length 11 and only has one element in index 10 and that is the image of the last song(that is the 10th song).
I'm a bit confused as to why the $scope.spotifyImg array only contains one element in index 10. Also why is the array of length 11 when the spotifyID is of length 10?
Any ideas of how I could solve this?
The problem is that getSpotify is run asynchronous, when the responses to these calls come in, i is probably set to spotifyID.length - 1 which means that all callback functions set the $scope.spotifyImg[spotifyID.length - 1] element.
Try this:
$scope.spotifyImg = [];
musicService.getBillboard($scope.date).then(function(data){
$scope.status = "";
$scope.songlist = data;
for (var i = 0; i < data.length; i++) {
$scope.getImage(data[i].spotify_id, i);
}
});
$scope.getImage = function(id, index) {
musicService.getSpotify(id).then(function(data){
$scope.spotifyImg[index] = data.album.images[0].url;
});
}
create separate function and put the content of for loop inside that function and call that function inside the loop
$scope.getImages = function() {
for (var i = 0; i < spotifyID.length; i++) {
if (spotifyID[i] !== null) {
sampleFunc(i);
}
}
}
function sampleFunc(i) {
musicService.getSpotify(spotifyID[i]).then(function(data) {
$scope.spotifyImg[i] = data.album.images[0].url; //returns the appropriate image from the Spotify Web API
});
}
I think reason you get only last index of an array is when you are calling promise inside loop, loop does't wait until the promise returns. it just keep executing.At the time promise returns loop is executed and it;s getting last index of the array. That's why you need to separately call the promise from for loop
You can use IIFE
(function(i){
musicService.getSpotify(spotifyID[i]).then(function (data) {
$scope.spotifyImg[i] = data.album.images[0].url;
});
})(i)
So,your getImages function should be like this.
$scope.getImages = function () {
for (var i = 0; i < spotifyID.length; i++) {
if (spotifyID[i] !== null) {
(function(i){
musicService.getSpotify(spotifyID[i]).then(function (data) {
$scope.spotifyImg[i] = data.album.images[0].url;
});
})(i)
}
}
}
Try using this code
Js code
var spotifyID = [];
$scope.spotifyImg = [];
musicService.getBillboard($scope.date).then(function(data) { //Response is top 10 songs for given date
$scope.status = "";
$scope.songlist = data;
for (var i = 0; i < data.length; i++) {
spotifyID[i] = data[i].spotify_id; //data[i].spotify_id returns the ID of the track, as given by the billboard API
}
$scope.getImages(0);
});
$scope.getImages = function(index) {
if (index == spotifyID.length) {
return;
}
musicService.getSpotify(spotifyID[index]).then(function(data) {
$scope.spotifyImg[index] = data.album.images[0].url; //returns the appropriate image from the Spotify Web API
// call recursive here
$scope.getImages(index++);
});
}
}
call your getimages function recursively so that will add you images in array.

Nested for loop with inner functions

In javascript For loop it's works fast and inner functions are not called. I am trying to store images in database using cordova. In my code for loop works fast and finished but I didn't get any base64 images.
for(var i = 0; i < pages.length; i++)
{
var cat_img = res.Catalogue[0].Catalogue_img;
var catalogue_image_id = cat_img[i].catalogue_image_id;
var catalogue_image = cat_img[i].catalogue_image;
getBase64FromImage(catalogue_image,function (baseData64) {
console.log("baseData64===="+baseData64);
insertPageData (catalogue_image, catalogue_image_id);
},function (error) {
console.log("error====="+error);
});
}
Thanks in advance!!
Your callback "function (baseData64)" will be executed only when the image is downloaded and converted to base64. At that point, the value of "calalogue_image" and "catalogue_image_id" will contain the value of the last element in the loop - with "i = pages.length"
That is, your for loop finishes probably before even the first image is downloaded.
Actually I think the valid behaviour is that you should see only the last image, with "i = pages.length" in the database.
Try this
var processImage = function (cImg,cImgId){
var catalogueImage = cImg;
var catalogueImageId = cImgId;
return function (baseData64) {
console.log("baseData64===="+baseData64);
insertPageData (catalogueImage, catalogueImageId);
}
}
for(var i = 0; i < pages.length; i++)
{
var cat_img = res.Catalogue[0].Catalogue_img;
var catalogue_image_id = cat_img[i].catalogue_image_id;
var catalogue_image = cat_img[i].catalogue_image;
getBase64FromImage(catalogue_image,
processImage(catalogue_image, catalogue_image_id) ,
function (error) {
console.log("error====="+error);
}
);
}

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.

One of my JavaScript variables seem to be getting reset after a jQuery call

My code sends requests to Twitter for search data gets responses in the from of JSON. After getting the JSON, it stores the count of responses that match a certain condition in an array.
Here is the code that makes the call to the function that queries Twitter.
$(document).ready(function() {
...
graph = new HighCharts.chart({
chart: {
events: {
load: function() {
console.log("events.load");
var that = this;
var update = function() {
if (polling) {
console.log("update()");
// The least index series will be nearest the x-axis
var stackNumber = 0;
var numTweets = updateValues();
console.log(numTweets + "");
for (var i = 0, currentSeries = that.series; i < currentSeries.length; i++) {
var x = (new Date()).getTime(), // current time
y = numTweets[i];
stackNumber += y;
currentSeries[i].addPoint([x, y], true, true);
}
}
}
// set up the updating of the chart each second
var series = this.series[0];
setInterval(update, 1000);
}
}
(I'm probably missing some brace somewhere in the code-paste here, but I know for sure that my problem isn't related to a missing brace)
And here is the function that actually queries Twitter using a series of jQuery calls. The updateValues() function (which is outside the document-ready section) goes as follows:
function updateValues() {
var url = "http://search.twitter.com/search.json?callback=?&q=";
var cls = "Penn_CIS240"
var query = "%23" + cls;
var voteCount = [0,0,0,0];
// create an array of zeros
//for (var i = 0; i < 4; i++)
// voteCount.push(0);
$.getJSON(url + query, function(json){
console.log(json);
$.each(json.results, function(i, tweet) {
var user = tweet.from_user_id;
if (user % 2 == 0) {
voteCount[0] += 1;
}
else if (user % 3 == 0) {
voteCount[1] += 1;
}
else if (user % 5 == 0) {
voteCount[2] += 1;
}
else {
voteCount[3] += 1;
}
console.log("updateValues() -> getJSON -> each -> voteCount = " + voteCount);
});
console.log("updateValues() -> getJSON -> voteCount = " + voteCount);
});
console.log("updateValues() -> voteCount = " + voteCount);
return voteCount;
}
What is happening is that the variable voteCount is getting incremented properly inside the jQuery calls. However, outside of the calls, it is getting reset. So the log outputs look something like this:
updateValues() -> getJSON -> each -> voteCount = [1,0,0,0]
updateValues() -> getJSON -> voteCount = [1,0,0,0]
updateValues() -> voteCount = [0,0,0,0]
Does this problem have to do with jQuery's asynchronous calls, and I'm having interesting variable modification conflicts? Or is it something else?
When you use asynchronous callbacks in JavaScript, they execute later... asynchronously. So if you have:
var x = 5;
console.log("before getJSON", 5);
$.getJSON("/some/url", function (json) {
x = 10;
console.log("inside callback", x);
});
console.log("after getJSON", x);
the output will be
before getJSON 5
after getJSON 5
inside callback 10
Any code you want to execute after the request returns must be inside the callback; putting it physically "after" the $.getJSON call will not suffice. You should think of $.getJSON as "firing off" the JSON-getting process, then immediately returning to you; only later, when your script is done executing normal code and the server has responded, will the JavaScript event loop say "hey I got a response and am idle; time to call that callback that was waiting on the response!"
Because of this, your updateValues function will need to accept a callback of its own in order to notify its own caller that the values have been updated; just calling updateValues will only fire off the value-updating process, and the values won't be updated later until that idle time. Something like:
function updateValues(onUpdated) {
var url = "http://search.twitter.com/search.json?callback=?&q=";
var cls = "Penn_CIS240"
var query = "%23" + cls;
var voteCount = [0,0,0,0];
$.getJSON(url + query, function (json) {
// use of json to update voteCount ellided
onUpdated(voteCount);
});
}
Then calling code uses it as
updateValues(function (voteCount) {
// use the updated vote counts inside here.
});

Categories