Arrays disappear outside of JSON request - javascript

I am attempting to set up an array with the various properties of a YouTube video (you may be thinking this is somewhat superfluous, however I am planning on adding other sources in the future). I am able to add these values into the array within the JSON request, but once I get out of it, they just disappear. Any ideas?
var socialPosts = new Array();
$.getJSON('https://gdata.youtube.com/feeds/api/videos?author=google&max-results=5&v=2&alt=jsonc&orderby=published', function(data) {
for(var i=0; i<data.data.items.length; i++) { //for each YouTube video in the request
socialPosts[i]={date:Date.parse(data.data.items[i].uploaded), title:data.data.items[i].title,source:"YouTube", thumbnail:data.data.items[i].thumbnail.hqDefault, url:'http://www.youtube.com/watch?v=' + data.data.items[i].id}; //Add values of YouTube video to array
}
console.log(socialPosts[0].date); //This returns the correct data
});
console.log(socialPosts[0].date); //This returns with undefined

You are trying to access results of Ajax asyn call which are not yet returned. You need to use result in call back function or pass the results to some function.
var socialPosts = new Array();
$.getJSON('https://gdata.youtube.com/feeds/api/videos?author=google&max-results=5&v=2&alt=jsonc&orderby=published', function(data) {
for(var i=0; i<data.data.items.length; i++) { //for each YouTube video in the request
socialPosts[i]={date:Date.parse(data.data.items[i].uploaded), title:data.data.items[i].title,source:"YouTube", thumbnail:data.data.items[i].thumbnail.hqDefault, url:'http://www.youtube.com/watch?v=' + data.data.items[i].id}; //Add values of YouTube video to array
}
console.log(socialPosts[0].date); //This returns the correct data
somefun(socialPosts[0].date);
});

Because that is an Ajax function and it happens async meaning the code outside the closure executes before the call is finished

Related

Jquery GET method inside a loop

I have an array of links with a url inside them, so I need to call 'get', wait for the response and extract what I want out of it and set an image's src to what I get back
I'm facing a problem where by the time the first 'get' is ready, the loop has finished, so basically every iteration of the loop gets the LAST 'data' response. Basically, only the last iteration of i gets a value, and even that's not always the right answer. It's just the last answer to come back
How do I go about fixing this issue?
for(i of instructors) {
jQuery( document ).ready($.get( i["image-link-post"], function( data ) {
i['image-link'] = data.guid.rendered;
}));
}
Since the loop is dealing with async calls, the iteration do not wait for ajax call to complete, and hence by the time the ajax call received a response, i is pointing to some other item of iteration. In this case, we need to maintain a local variable of iterating item and then pass the local reference to the ajax response handler. Checkout with below refactored code:
// Changed var image to let image
for (i of instructors) {
let image = i;
jQuery(document).ready($.get(image["image-link-post"], function (data) {
image['image-link'] = data.guid.rendered;
}));
}
// Below code also works
for (i of instructors) {
(function (image) {
jQuery(document).ready($.get(image["image-link-post"], function (data) {
image['image-link'] = data.guid.rendered;
}));
}(i));
}

Calling an API based off a file synchronously in JavaScript

SOLVED: I solved my problem by doing each XMLHttpRequiest() recursively. Basically at the end of my xhr.onload, I would make another request and actively check if I've reach the end of my data - when I have I return.
I'm fairly new in JavaScript and have some familiarity with the D3 Library. I'm trying to read a CSV file from my computer using the D3 Library and sending specific information from my file to an API through an XMLHttpRequest().
With each call to the API which returns a JSON object to me, I store that object in a dataset for later use. I'm trying to have it so that my whole CSV file is read and processed before I work with the dataset, however I'm running into a problem since the API calls are asynchronous.
My code looks something like this:
var myData = [];
d3.csv("myFile.csv", function(data)
{
for (var i = 0; i < data.length; i++)
// Get appropriate data from data object
// Make API call with XMLHttpRequest() and store in myData array
});
// Handle fully updated myData array here
As it is, my code currently goes through my loop in almost an instant and makes all the API calls asynchronously and then proceeds to work on my data without waiting for anything to update.
Is there a way to ensure that my CSV file has been processed and all the API calls have returned before I can work with this dataset? I've tried callback functions and promises but had no success.
You can easily do this with a simple counter
var counter = 0;
var myData = [];
d3.csv("myFile.csv", function(data)
{
for (var i = 0; i < data.length; i++){
// Get appropriate data from data object
$.get("your/api/path", function(result){
counter++; // this is important. It increments on each xhr call made.
myData.push(result);
if(counter === data.length) cb(myData); // This will check if the current xhr request is the last xhr request. If yes then call our cb function.
});
}
});
function cb(data){
// This will run only when all the http requests are complete
// Do something with data
}
All this code does is, it makes sure that all of our requests should be completed first before calling our cb function (here you will write your further logic). This approach guarantees that cb will run only when all xhr requests are completed.
I think the answer in this post could help
d3: make the d3.csv function syncronous
You can as well use the Promise API.

Dealing with facebook Graph API objects in javascript

I am trying to access specific albums via their location from a Facebook page via a graph API call and ultimately display them on a webpage.
Essentially I think I need to loop through the object that Facebook sends back (response in this case) and only store objects which contain the substring "Germany" in the location description to the variable albums. Currently nothing happens in the console when I trigger the method.
I'm kind of stuck at this point, I can make API calls and have them returned from the specific page via other functions, so my permission seems to be fine, I'm just structuring this function incorrectly (I think, I'm relatively new to JS and Jquery).
model.getPhoto = (function(data){
var albums;
FB.api(
'/--USER ID GOES HERE--/albums',
'GET',
{"fields":"link,location"},
function(response){
for (var i=0; i<response.length; i++){
if (response.albums.location[i] = "Germany"){
albums = response.albums.location[i];
i++;
}
console.log(albums);
}
}
);
});
You are setting model.getPhoto as a new function. If your code is complete, you never call this function. I added some lines then you can try to fix and see some results... Also changed some lines, created albums as an Array and put i++ outside of if to execute for loop correctly.
Last line calls your function.
model.getPhoto = (function(data){
FB.api('/--USER ID GOES HERE--/albums',
'GET',
{"fields":"link,location"},
function(response){
var albums = new Array();
for (var i=0; i<response.length; i++){
if (response.albums.location[i] == "Germany"){
albums.push(response.albums.location[i]);
}
i++;
console.log(albums);
}
});
});
model.getPhoto({var1: "value1"});
I suggest you play more with javascript and logics, take a look inside some libraries like jQuery itself, as you are not using it here, just pure JS, and have fun!
EDIT
When comparing, you must use == instead of =
Best,
Eder

How can I pass data read from a JSON file to the rest of my Javascript code?

I'm new in the scripting and web world and have been trying to work through an issue I've been having. I am reading data from a local JSON file, and have been able to use jQuery.getJSON and jQuery.parseJSON successfully, but I am trying to use the data outside of the getJSON callback function and am having issues. I think it comes down to me not fully understanding the correct way to do this, and that's where I'm looking for your help. Here's my code:
var names = new Array();
$.getJSON('ferries.json', function(data) {
var jsondata = $.parseJSON(JSON.stringify(data));
var length = jsondata.nodes.length;
for (var i = 0; i < length; i++) {
names[i] = String(jsondata.nodes[i].name);
}
});
console.log('Names: ' + names[0]);
The final line returns undefined. If I were to write that line right after the for loop, it would return the desired value. Here's how the JSON file is structured:
{
"nodes":[
{
"name":"John"
},
...
{
"name":"Joe"
}
]
}
Any help would be appreciated - thanks!
Edit: One last thing, it seems that the final line (console.log(...)) executes before the $.getJSON bit, which confuses me as well.
$.getJSON runs asynchronously. The function that you pass to it is a "callback", which means that it gets called when getJSON comes back from doing its thing.
If you want to do something with the JSON data that you get back, you must wait for the callback to execute.
Also, on a side note, $.parseJSON(JSON.stringify(data)) is redundant. The data object is already a perfectly usable object with your data in it, but you're turning that object back into a JSON string and then immediately back into an object. Just use data as is. For more information, check out the jQuery API docs for getJSON.

Ajax HEAD request via Javascript/jQuery

I seem to be having some issues with making HEAD requests, and preserving the integrity of data in an array.
Given this snippet:
var imageTemp = Array();
$('*')
.each(function(index){
if($(this).css('background-image') != 'none'){
imageTemp.push($(this).css('background-image').slice(5, -2));
}
});
I capture the URLs of all background-images on a given page. Now, trying to grab the size of each image via HEAD requests for Content-Length, I use this snippet:
var imageData = Array();
for(var i = 0; i < imageTemp.length; i++){
ajaxSizeRequest = $.ajax({
type: "HEAD",
async: true,
url: imageTemp[i],
success: function(message){
imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
}
});
}
However, when I dump imageData via console.log, I each element (which should be an array containing the URL and the content-length) ends up as [undefined, XXXX] where XXXX is always the size of the last requested Content-Length
I'm stumped, though it appears to be a timing/scoping issue. Do I have a sort of race-condition occuring here?
The problem is that the single variables i and ajaxSizeRequest being captured by the callback function are the same variables for all instances of the callback function. I think if you call a function and pass the index variable to it and, at the same time, scope the request variable locally to the function itself use the response parameter of the done handler, you should end up with independent variables captured by the callback. It should then reference each array element and each response variable correctly.
var imageData = Array();
for(var i = 0; i < imageTemp.length; i++){
updateImageData( i );
}
function updateImageData( i )
$.ajax({
type: "HEAD",
async: true,
url: imageTemp[i],
}).done(function(message,text,jqXHR){
imageData.push([imageTemp[i], jqXHR.getResponseHeader('Content-Length')]);
});
}
looks like your i isnt properly closed-in
in addition, you can't use ajaxSizeRequest because it too is pointing to just one request (probably the last, because the loop will execute very fast)
just wrap your success callback function as follows, changing the reference to ajaxSizeRequest:
success: (function(i){
return function(data,status,xhr){
imageData.push([imageTemp[i], xhr.getResponseHeader('Content-Length')]);
};
})(i)
You can scope I like so:
success: function(i){
return function(message){
imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
}
}(i)
You have a single i variable which is shared by all of the callbacks.
Since AJAX is asynchronous, all of the callbacks run after your loop is finished, and they all get the same i.
To fix this, you need to move the AJAX call into a separate function that takes i as a parameter.
Thus, each callback will get a separate i parameter.
If anyone still having trouble with this, and since this post is, like, 5 years-old already, here's a more 'modern' version of the answer: just use let instead of var in the original post's for loop.
Info: Is there any reason to use the “var” keyword in ES6?
and: MDN - Let syntax

Categories

Resources