jQuery each loop variable data lost [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
having a little trouble with my variable scope in jQuery, how come if I do the console.log outside the .each loop I get an empty array on $stockData ? (if i do it inside the .each, it works just fine, logs the array each time a value is added)
$(document).ready(function(){
// stock data will contain all the merged data from the database and yahoo queries
var $stockData = new Array();
// get data from yahoo and merge with dbData, add to stockData array
$.getJSON( "/get_portfolio.php", function(dbData) {
$.each( dbData, function(index) {
var stock = dbData[index]
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+stock.stock_symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
crossDomain: true
}).success(function(data){
var quote = data.query.results.quote;
$.extend(quote, stock);
$stockData.push(quote);
}); // end success
});// end each
}); // end getJSON
console.log($stockData);
}); // end document.ready

when you call
$.getJSON( "/get_portfolio.php", function(dbData) { ... });
this part:
function(dbData) { ... }
doesn't run right away. JavaScript says: "oh you did a http request? I'll hold onto this function you gave me and run it after the request is done". And the rest of your code will keep on running, so this:
console.log($stockData);
will run first. So the actual order of execution here is:
you run getJSON
console.log runs
the HTTP request finishes and your callback runs
put the console.log inside the getJSON block, right after your .each loop:
$(document).ready(function(){
// stock data will contain all the merged data from the database and yahoo queries
var $stockData = new Array();
// get data from yahoo and merge with dbData, add to stockData array
$.getJSON( "/get_portfolio.php", function(dbData) {
var requestsDone = 0;
$.each( dbData, function(index) {
var stock = dbData[index]
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+stock.stock_symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
crossDomain: true
}).success(function(data){
var quote = data.query.results.quote;
$.extend(quote, stock);
$stockData.push(quote);
if(++requestsDone == dbData.length) done();
}).error(function(){
if(++requestsDone == dbData.length) done();
});
});// end each
function done() {
console.log($stockData); // put this here
}
}); // end getJSON
}); // end document.ready

You need to wait getJSON function be completed, try this:
$(document).ready(function(){
// stock data will contain all the merged data from our database and yahoo queries
var $stockData = new Array();
// get data from yahoo and merge with dbData, add to stockData array
$.getJSON( "/get_portfolio.php", function(dbData) {
$.each( dbData, function(index) {
var stock = dbData[index]
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+stock.stock_symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
crossDomain: true
}).success(function(data){
var quote = data.query.results.quote;
$.extend(quote, stock);
$stockData.push(quote);
}); // end success
});// end each
console.log($stockData);
}); // end getJSON
});

Related

Accessing an Array returned by a function in JavaScript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I've got the following code:
$(document).ready(function() {
var blu = getData();
console.log(blu); //this shows full the array in the console
console.log(blu.length); //this gives back 0
});
With the following function getData()
function getData() {
var arr = [];
var json;
$.ajax({
url: "someurl.com",
dataType: 'json',
data: json,
success: function(json) {
var x = json.somejson.somenumericvalue //gets the amount of dataentries
for (i = 0; i <= x - 1; i++) {
arr.push(json.feeds[i].field1); // fill up array with the values from the json feed
}
} //end of success function
}); //end of ajax
console.log(arr.length) //shows the correct length of the array
return arr;
} //end of function getData
Problem is I want to access the values and do methods (like .length) with the array which is filled in the function but it somehow does not work. Anyone can help out?
Cheers.
You can use $.each or for in loop
E.g.
$.each(Blu, function (i, v){//do whatever with array values, i: index, v: value}
Or
For(i in Blu){//i: index, access your value by Blu[I] & do whatever with your value}
Hope it'll help you out
The json data returned by the ajax call must be accessed by object notation if it is a named array. To retrieve the length of such an data object use:
Object.keys(data.datanode).length
It is not clear what your json looks like, you probably need to iterate through it. Assuming that you want to iterate through json.feeds:
function getData(){
var arr = [];
var json;
$.ajax({
url: "someurl.com",
dataType: 'json',
data: json,
success: function(json){
for(var i in json.feeds) {
arr.push(json.feeds[i].field1); // fill up array with the values from the json feed
}
console.log(arr.length)//shows the correct length of the array
return arr;
} //end of success function
}); //end of ajax
}//end of function getData
Also note where console.log and return is. I would suggest reading a basic book about javascript, specifically closures and variable scope. That's why your code doesn't work and the problem is not in ajax, json, or object iterating.

jquery global variable ajax returns null [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
Created a fiddle for this as it is so simple but yet it doesn't work;
var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
function getData (url) {
return $.ajax({
'type': "POST",
'url': url
});
};
$(document).ready(function(){
var a = null;
getData(url).done(function(data){ a = data; });
alert(a);
});
early morning perhaps?
Fiddle: https://jsfiddle.net/nextgenmappinginc/r88356tu/
Goal:
I have multiple local files which contain geojson data. Which I will be returned to me as an array. I want to loop through these create objects and push these objects into an array. Then from the new array created by all of these ajax calls. I want to pass this array to a function that will execute open layers code.
updated and completed different fiddle
https://jsfiddle.net/nextgenmappinginc/x1yasngy/
But. Problem remains. Even when you pass through ASYNC The function is only fired upon request. Then it remains in the function. So technically why can't it pass it to another function that can then console it?
In the fiddle you can simply change the urls so that you can get request response
//var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
var url = {url : 'clientData/10BC99F2-05FD-4847-A277-2979C83BB42A/geojson/E36CC45E-C1B8-4C26-A714-EBA91ACE7C1C.js'}
var files = [];
files.push(url);
function getData (files) {
var fileObjects = [];
for (i=0; i<files.length; i++){
$.ajax({
'type': "GET",
'url': files[i].url,
success: function (response){
fileObjects.push(response);
}
});
}
consoleMe(fileObjects);
}
function consoleMe(data){
console.log(data);
}
getData(files);
add async:false, in your ajax code. Remove this line
getData(url).done(function(data){ a = data; });
and add below line
getData(url).done(function(data){ a = data; });
Try below example this will work for sure
var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
function getData (url) {
return $.ajax({
'type': "POST",
async:false,
'url': url
});
};
$(document).ready(function(){
var a = null;
a = getData(url);
console.log(a);
alert(a);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
You want to "get" data but you do a post request to the API. Secondly .done is an asynchronous function. It will be execute when the API sends you the data.
Code
var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
function getData (url) {
return $.ajax({
'type': "get",
'url': url
});
};
$(document).ready(function(){
getData(url).done(function(data){
// here you have access to data
alert(data)
});
});

How to display array content at the end of getjson call?

i have a function that makes 2 getjson calls and writes the responses to an array . i used the following code at the end of my second getjson call:
alert(files.length);
print_r(files);
console.log(files);
However , the files.length tells me the number of items in the array but print_r(files); and console.log are not working ? i want to print the array items to confirm i got correct items but array print doesn't work ! could any one tell me how to fix this problem ?( my goal is to later on sort this array and remove duplicates and filter... )
<script>
var files = new Array();
function pushtoArray(){
//first getjson call
var url1 = "https://spreadsheets.google.com/feeds/list/xxxxx/xxxxx/public/values?alt=json";
$.getJSON(url1, function(data) {
var entry = data.feed.entry;
$(entry).each(function(){
// Column names are name, age, etc.
count++;
files.push({ url: this.gsx$url.$t, filename: this.gsx$name.$t });
$('.results').prepend('<h2>'+this.gsx$name.$t+'</h2><p>'+this.gsx$url.$t+'</p>');
});
alert(files.length);
print_r(files);
console.log(files);
});//end of ajax call
//second getjson call
var url2 = "https://spreadsheets.google.com/feeds/list/xxxxx/xxxxx/public/values?alt=json";
$.getJSON(url2, function(data) {
var entry = data.feed.entry;
$(entry).each(function(){
// Column names are name, age, etc.
count++;
files.push({ url: this.gsx$url.$t, filename: this.gsx$name.$t });
$('.results').prepend('<h2>'+this.gsx$name.$t+'</h2><p>'+this.gsx$url.$t+'</p>');
});
alert(files.length);
print_r(files);
console.log(files);
});//end of ajax call
};//end of function
</javascript>
html code:
<body onload="pushtoArray()">
Print_r is a PHP function, in javascript you can only use console.log.

How to read XML data with $.ajax and return the value within a $.each loop

For one part of our study-project we need to compare an array of Strings with a xml database. So my idea was to divide in 2 parts (because we need the compare-function twice). First I loop through the array with $.each and then I pass the value to another function that makes an ajax request to the xml, compares the value with each data in xml and if something found, it pushes it to an array which should be returned at the end.
In one function the jquery.each() is called:
function doSomething(){
liste = ["test1","test32","test22"];
$.each(liste, function(index, value){
var checkIt = compareDataBase(value);
if(checkIt.length>0) //do Something
});
}
and this is the function that compares the value and returns an array:
function compareDataBase(foo){
var lists = [];
$.ajax({
type:"GET",
url: "data/database/datenbank.xml",
dataType:"xml",
success: function(xml){
$(xml).find('product').each(function(index, element){
var current_product = $(this).text();
if(current_product.indexOf(foo)>-1)lists.push(current_product);
});
},
error: function(){
console.log("Fehler bei Produkte auslesen");
}
});
return lists;
}
But sadly that doesn't work. "checkIt" is always undefined because it doesnt wait for the ajax...
I tried to use the $.when function or give the compareDataBase()-function a callback but somehow that didnt work neither (I think because
I declared it wrong)
So maybe someone knows how to make this right?
Thanks for your help!
br sebi
You should use callbacks (or promises which are a variation on callbacks), the following solution example uses callbacks:
function compareDataBase(foo, callback){
var lists = [];
$.ajax({
type:"GET",
url: "data/database/datenbank.xml",
dataType:"xml",
success: function(xml){
$(xml).find('product').each(function(index, element){
var current_product = $(this).text();
if(current_product.indexOf(foo)>-1)lists.push(current_product);
});
// notify the callback with the result lists here
callback(lists);
},
error: function(){
console.log("Fehler bei Produkte auslesen");
}
});
}
function doSomething(liste, index){
if ( index < liste.length )
{
compareDataBase(liste[index], function(checkIt){
if(checkIt.length>0) //do Something
// process next list item using callbacks
doSomething(liste, index+1);
});
}
}
// start the process
doSomething(["test1","test32","test22"], 0);
Note that the example solution processes each list item only after the previous item has been processed (it kind of synchronises the callbacks, each callback will call the next one). One can remove this feature and process all asynchronously as follows:
// process all async
var liste = ["test1","test32","test22"];
for (var i=0; i<liste.length; i++) doSomething([liste[i]], 0);

How to deal with a group of deferred's when one of them fails

I have a series of ajax calls that fill columns on a page.
var doneDefers = function(defer) {
// leftColDefer is another deferred that sets some header info
$.when(defer, leftColDefer).done(function(req1, req2){
var data = req1[0],
head = req2[0];
// spit this data out to elements on the page
});
};
for(i=0;i<window.ids.length;i++){
defer[i] = $.ajax({
url: 'api/get_runs_stats.php',
type: 'GET',
dataType: 'json',
data: {
run_id: window.ids[i]
}
});
doneDefers(defer[i]);
}
This works fine. If an ajax call fails, nothing is spit out and all is right with the world.
Now I want to do some calculations based on all the data that got spit out.
$.when.apply(null, defer)
.done(function() {
var args = Array.prototype.slice.call(arguments);
calcDeltas();
})
.fail(function() {
var args = Array.prototype.slice.call(arguments);
console.log('in list fail');
});
The done function works fine none of the ajax calls fail. If one of them fail, I go into the fail function and I don't have access to any of the return data from the other runs. The arguments array only has the failed call's data.
I would like to do my calculations on the data sets that passed. How can I get to the data from the good calls when one of them fails?
I'm not sure this is the simplest solution but it stands a chance of working.
var ajax_always_promises = [],//to be populated with promises that (barring uncaught error) are guaranteed to be resolved.
data_arr = [],//an array to be (sparsely) populated with asynchronously delivered json data.
error_arr = [];//an array to be (sparsely) populated with ajax error messages.
$.each(window.ids, function(i, id) {
var dfrd = $.Deferred();
var p = $.ajax({
url: 'api/get_runs_stats.php',
type: 'GET',
dataType: 'json',
data: {
run_id: window.ids[i]
}
}).done(function(json_data) {
data_arr[i] = json_data;//intentionally not `data_arr.push(json_data);`
}).fail(function(jqXHR, textStatus, errorThrown) {
error_arr[i] = textStatus;//intentionally not `error_arr.push(textStatus);`
}).always(dfrd.resolve);
ajax_always_promises[i] = dfrd.promise();
doneDefers(p);
});
$.when.apply(null, ajax_always_promises).done(function() {
//The data in the (sparsely) populated arrays `data_arr` and `error_arr` is available to be used.
var i, id, success_count=0, error_count=0;
for(i=0; i<Math.max(data_arr.length,error_arr.length); i++) {
//Here, the index i corresponds to the original index of window.ids ...
//...that's the advantage of sparsely populating the arrays.
id = window.ids[i];
if(data_arr[i]) {
//Here, do whatever is required with `data_arr[i]`, and `id` if needed.
success_count++;
}
else if(error_arr[i]) {
//Here, do whatever is required with `error_arr[i]`, and `id` if needed.
error_count++;
}
}
console.log("Success:errors: " + success_count + ':' + error_count);
});
Untested - may well need debugging

Categories