jQuery.each() and Array Manipulation - javascript

Here's my code:
$(document).ready(function() {
var myArray = [];
$.getJSON("some url",function(data){
$.each(data, function(){
myArray.push("a string" + this);
});
alert(myArray);
});
//alert(myArray);
});
The code as shown is working just fine and it displays the array and its contents.
However, when I try to display the array by having the command line right after the $.each code block (commented out in the sample code), the array and its contents are not displayed. An empty/ blank message is returned instead.
Why is this happening and how can I fix it? I'd like to have the command "alert(myArray);" right after the $.each block.
Thank you in advance!

var myArray = [];
var jqxhr = $.getJSON( "some url", function(data) {
$.each(data, function(){
myArray.push("a string" + this);
});
}) ;
jqxhr.complete(function() {
console.log(myArray);
});
jQuery XHR object, or "jqXHR," is returned by $.getJSON()
When the request is already complete, the .complete() callback is fired immediately.

Related

Jquery each loop doesn't display JSON item's properties

Edited2: Here is a pic of how one object looks like. All fields for all objects are filled.
Edited: So the problem appears to be the each loop. I console.logged data and it showed it in an array style. But for some reason, when i try to print the object's age, f.ex., it shows up as undefined.
I am doing a small script for displaying information from a json-file with jquery and ajax. I got the ajax part working (I think) but I can't get my function to print the JSON object data.
So I am trying to display JSON object's with Jquery but it doesn't do anything. The ready function prints out done and complete.
$(document).ready(function(){
$.ajax({
url: "file.json",
cache: false
}).done(function(data) {
console.log("done");
showData(data);
}).fail(function() {
console.log("error");
}).always(function() {
console.log("complete");
});
});
function showData(data) {
$.each(data.cats, function(index, kitty) {
var div = $("<div></div>");
div.addClass("catContainer");
var image = $("<img></img>");
image.addClass("catImage");
image.src="kitty.image";
var header = $("<p></p>").text(kitty.color);
header.addClass("header");
var age = $("<p></p>").text(kitty.age);
var text = $("<p></p>").text(kitty.text);
text.addClass("text");
var price = $("<p></p>").text(kitty.price);
div.append(image,header,size,text,price);
$("div#cats").append(div);
});
}
I also tried this loop but it prints 'undefined' to the div:
$(data).each(function(i, kitty) {
$('#cats').append(kitty.price);
// I am sorry, I am noob. Hope this post is according to the instructions.
One issue is with your image.src. When you set it to "kitty.image", this would literally assign that string. So instead of:
image.src = "kitty.image",
Use:
image.attr("src", kitty.image);
Or:
image[0].src = kitty.image
The latter here, since image is a jQuery Object, would not have src as an index. So we can call image[0] to get the HTML Element, that we can then assign the src.
Consider the following.
$(function() {
function showData(d, o) {
$.each(d, function(index, kitty) {
console.log("Adding Kitty", kitty);
var div = $("<div>", {
class: "catContainer"
}).appendTo(o);
$("<img>", {
class: "catImage",
src: kitty.image
}).appendTo(div);
$("<p>", {
class: "header"
}).html(kitty.color).appendTo(div);
$("<p>").html(kitty.age).appendTo(div);
$("<p>", {
class: "text"
}).html(kitty.text).appendTo(div);
$("<p>").html(kitty.price).appendTo(div);
});
}
$.ajax({
url: "file.json",
cache: false,
success: function(data) {
showData(data.cats, "#cats");
console.log("Success");
},
error: function(x, e, n) {
console.log("Error", x, e, n);
}
});
});
Based on your post, data is an Object. data.cats is an Array of Objects. So we will iterate the Array with $.each() using data.cats. I also pass in the target object ID. .appendTo() accepts a few items:
A selector, element, HTML string, array of elements, or jQuery object; the matched set of elements will be inserted at the end of the element(s) specified by this parameter.
See More: https://api.jquery.com/appendto/
It is then just a matter of creating each of the elements. With the $("<div>"), jQuery will handle wrapping the element for us. We can also pass in an Object with the attributes, like class. We can chain to the jQuery Object that is the result and would advise using .html() versus .text(), yet there is nothing wrong with doing either.

JQuery: parsing ajax call versus imbedded str

I am confused because I have two functions, one using ajax to get the data and the other getting it from a string.
function loadMenuData() {
$.ajax({
url: "./shoulders.json",
success: function(data) {
dataObj = $.parseJSON(data);
$.each(dataObj, function( key, value) {
$(document).find("#dropDownDest").append($('<option></option>').val(value.id).html(value.name));
});
}
});
}
function loadMenuDataX() {
var str = '[{"id":"A","name":"Bart"},{"id":"B", "name":"Joe"},{"id":"C", "name":"Gomer"}]';
dataObj = $.parseJSON(str);
$.each(dataObj, function( key, value) {
$(document).find("#dropDownDest").append($('<option></option>').val(value.id).html(value.name));
});
}
I created the file shoulders.json buy pasting the str between the single quotes ' into the file. If I call loadMenuX, it fills in the <select></select> correctly. If I call loadMenu, it doesn't fill anything in.
I have tried JSON.parse instead of the above and get the same behavior.
I was unable to use $("#dropDownDest") and had to use $(document).find. Why?
Hitting the DOM each loop seems to be excessive. What would be a better way to do the ajax version THAT WOULD WORK and be better?
What would be a better way to do the ajax version THAT WOULD WORK and be better?
Because you're trying to get JSON file the better way is using jQuery.getJSON(), so you will be sure that the returned result is in json format :
$.getJSON( "./shoulders.json", function( json ) {
$.each(json, function( key, value) {
$("#dropDownDest").append('<option value="+value.id+">'+value.name+'</option>');
});
});
Hope this helps.

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

After leaving .get array loses data

I know there is something I am missing about Ajax but I need help to understand. In the following code myArray has its content at label "A" but is empty at label "B". The purpose of the code is to read multiple csv files, store some values from each of the files and use myArray later in the script. I know there must be something with vars in the Ajax request (.get). Thanks
var myArray = [];
var lines = [];
$.each(fileNames, function(lineNo, file)
{
$.get(file, function(data)
{
lines = $.csv.toObjects(data);
$.each(lines, function(lineNo, line)
{
... code ...
myArray.push(someValue);
});
--- A ---
});
--- B ---
});
$.get is asynchronous.
Any code placed at B will run while the get is happening.
Place any code you want to act on MyArray inside the function supplied to get, or place another call inside the get function to act on your data.
$.get(file, function(data)
{
lines = $.csv.toObjects(data);
$.each(lines, function(lineNo, line)
{
... code ...
myArray.push(someValue);
});
// myArray is ready here. Place any code that acts on it here...
});
// myArray may not be ready here, since the `get` hasn't finished yet.
The problem is that the get callback gets executed asynchronously when the get request return, but the code below the get call gets executed right away, before the callback.
You could execute synchronously replacing get with ajax async=false. This will be a bit slower as each call would not begin till the previous one ended.
var myArray = [];
var lines = [];
$.each(fileNames, function(lineNo, file)
{
$.ajax({
url: file,
success: function(data) {
lines = $.csv.toObjects(data);
$.each(lines, function(lineNo, line)
{
... code ...
myArray.push(someValue);
});
},
async:false
});
});
If you don't like the async:false approach you could use this:
var myArray = [];
var lines = [];
var count = 0;
$.each(fileNames, function(lineNo, file)
{
$.get(file, function(data)
{
lines = $.csv.toObjects(data);
$.each(lines, function(lineNo, line)
{
... code ...
myArray.push(someValue);
});
}).done(function(){
count++;
if(count > fileNames.lenght){
// Code to use array goes here
}
});
});

Javascript/jQuery variables not giving expected values

Like others before me I'm struggling with scope in Javascript. (That and trying to read the darn stuff). I have checked some of the previous threads on this question but I cant seem to get them to apply correctly to my issuue.
In the example below, I want to manipulate the values in the tagsArr array, once the array has been fully populated. I declared the tagsArr variable outside the scope of the function in which it is populated in order to access it globally. But the variable doesn't seem to have the scope I expect - tagsArr.length is 0 at the point where I call output it to console on line 16.
$(function(){
var apiKey = [myapikey];
var tags = '';
var tagsArr = new Array();
$.getJSON('http://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&api_key=' + apiKey + '&user_id=46206266#N05&extras=date_taken,tags&format=json&jsoncallback=?', function(data){
$.each(data.photos.photo, function(i, item) {
var photoID = item.id;
$.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', function(data){
if (data.photo.tags.tag != '') {
$.each(data.photo.tags.tag, function(j, item) {
tagsArr.push(item.raw);
});
}
});
tags = tagsArr.join('<br />');
console.debug(tagsArr.length);
});
$('#total-dragged').append(data.photos.total);
$('#types-dragged').append(tags);
});
});
Your calls to getJSON are asynchronous. Hence all the calls to the inner getJSON will still be outstanding by the time the console.debug line is reached. Hence the array length is still 0.
You need to run some extra code once the final getJSON call has completed.
$(function(){
var apiKey = [myapikey];
var tags = '';
var tagsArr = new Array();
$.getJSON('http://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&api_key=' + apiKey + '&user_id=46206266#N05&extras=date_taken,tags&format=json&jsoncallback=?', function(data){
var totalExpected = data.photos.total;
var totalFetched = 0;
$.each(data.photos.photo, function(i, item) {
var photoID = item.id;
$.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', function(data){
if (data.photo.tags.tag != '') {
$.each(data.photo.tags.tag, function(j, item) {
tagsArr.push(item.raw);
totalFetched += 1;
if (totalFetched == totalExpected)
fetchComplete();
});
}
});
function fetchComplete()
{
tags = tagsArr.join('<br />');
console.debug(tagsArr.length);
}
});
$('#total-dragged').append(data.photos.total);
$('#types-dragged').append(tags);
});
});
This works assuming the total number of photos doesn't excede the default 100 per page, other wise you would need to tweak it.
That said I don't think using .each to fire off loads of getJSON requests makes a great deal of sense. I would refactor it so that only one call to getJSON is outstanding at any one time. Have the callback of one issue the next getJSON for the next photo until all have been pulled then do your completed code.
$.getJSON is asynchronous (the a in ajax). That means that by the time you get to console.debug(), getJSON is still getting. You'll need to do some extra work in the JSON callback.
The reason for this is that getJSON is an asynchronous request. after the call to $.getJSON, the javascript engine will move immediately on to the following two lines of code, and will output the length of your array, which is by then, zero-length. Not until after that does the getJSON request receive a response, and add items to the array.
The getJSON function is asynchronous, so when you call the debug function the array is still empty because the requests are not completed. Use the $.ajax function and set async:false and it will work.
$.ajax({
type: "GET",
url: 'http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?',
dataType: "json",
async:false,
success:function(data){
if (data.photo.tags.tag != '') {
$.each(data.photo.tags.tag, function(j, item) {
tagsArr.push(item.raw);
});
}
}
});
This isn't a scope issue - the problem is that getJSON is asynchronous, so it continues executing immediately after sending the request to flickr. By the time the browser executes console.debug the request hasn't returned and you haven't finished handling the response (and therefore haven't pushed any items into the array yet).
To solve this, find all the code that should only be executed when the array is full and move it into your getJSON callback method:
if (data.photo.tags.tag != '') {
$.each(data.photo.tags.tag, function(j, item) {
tagsArr.push(item.raw);
});
tags = tagsArr.join('<br />');
console.debug(tagsArr.length);
$('#total-dragged').append(data.photos.total);
$('#types-dragged').append(tags);
}
You may want to check the answer to this question I posted. There is some good information on scope issues in javascript.

Categories