I have the following JSON:
{"data":[{"id":1,"client_id":1},{"id":2,"client_id":1}]}
I'm trying to do a for...in but something is not going well.
Look at my code:
for (post in data) {
console.log(post.client_id); //return undefined
}
But if I do this:
for (i=0 ; i<data.length; i++) {
console.log(data[i].client_id); //return the correct value
}
Why can't I iterate with for..in in this case?
The value of the "data" property is an array. You need:
for (var i = 0; i < json.data.length; ++i)
console.log(json.data[i].client_id);
That's assuming that the JSON has been parsed and stored in a variable called "json". If it's actually called "data", then it'd be "data.data" instead of "json.data".
You really should not use for ... in loops for real arrays. It's a bad habit for a variety of reasons. Use a numeric index or something like the .forEach() facilities available in newer browsers.
First off, you should NEVER iterate arrays with for/in. That structure iterates properties of the object. You will get all the array elements, but you may also get other iterable properties of the object too.
Arrays should always be iterated with a traditional for loop as in:
for (var i = 0; i < arr.length; i++).
Second off, you have to make sure you're following your own data structure properly. You have this:
var item = {"data":[{"id":1,"client_id":1},{"id":2,"client_id":1}]};
which spread out some more looks like this:
var item = {
"data":[
{"id":1,"client_id":1},
{"id":2,"client_id":1}
]
};
So, your JSON is an object. That object has one property in it called data and that one property's value is an array, which contains objects. You would get the first item in the array with this:
item.data[0]
Or the properties on that object with this:
item.data[0].id
item.data[0].client_id
You would iterate all the items in that array like this:
for (var i = 0; i < item.data.length; i++) {
// access each object in the array
item.data[i].id
item.data[i].client_id
}
it should be like this:
for (var post in data) {
console.log(data[post].client_id); //return undefined
}
this is the correct form to iterate using for... in
for (post in data) {
console.log(post.client_id); //return undefined
}
you're doing this wrong, try it like this:
for (post in data) {
console.log(data[post].client_id); //return undefined
}
you should actually also include a filter, since stuff from the prototype can leak in:
for (post in data) {
if (data.hasOwnProperty(post)) {
console.log(data[post].client_id); //return undefined
}
}
It's because of the structure of your JSON. Notice that you've got an outer object with only a single top-level property: data.
{ "data":
[
{"id":1,"client_id":1},
{"id":2,"client_id":1}
]
}
data doesn't have a client_id property: it's an array of the sub-entries that you're trying to iterate over, and those have client_id properties. This is why your loop that indexes data works.
Related
I am working on an exercise where I prompt the user for a list of names, store the list of names in an array, sort the array in ascending order, and print the list of names (one per line). When I do so, I see a numeric value displayed instead of one name per line. Why is this happening?
var namesArray = [];
do {
var names = prompt("Enter a name: ");
namesArray.push(names);
} while (names != "")
namesArray.sort();
for (var name in namesArray) {
document.write(name);
}
When you use this construct:
for (var name in namesArray) {
the value of name will be the index in the array (the property name). If you want the actual value in the array, you have to use that property name/index to get the value:
document.write(namesArray[name]);
Of course, you really should not iterate arrays that way in the first place because that iterates all the enumerable properties of the array object (potentially including non array elements) as you can see in this example. Instead, you should use a traditional for loop as in this code example that follows:
var namesArray = [];
do {
var names = prompt("Enter a name: ");
namesArray.push(names);
} while (names != "")
namesArray.sort();
for (var i = 0; i < namesArray.length; i++) {
document.write(namesArray[i]);
}
Other options for iterating the array:
namesArray.forEach(function(value) {
document.write(value)
});
Or, in ES6, you can use the for/of syntax which does actually work how you were trying to use for/in:
for (let value of namesArray) {
document.write(value);
}
You also may want to understand that using document.write() after the document has already been parsed and loaded will cause the browser to clear the current document and start a new one. I don't know the larger context this code fits in, but that could cause you problems.
First, in a for..in loop, here name represents the keys and not the values in your array (you should use namesArray[name])
Also there is another important thing to note. An array is not recommended to be looped through using for..in and if so, you should do it like this:
for (var key in array) {
if (array.hasOwnProperty(key)) {
// then do stuff with array[key]
}
}
The usual preferred ways to loop through an array are the following:
A plain for loop
for (var i = 0, l = array.length; i < l; i++) {
// array[i]
}
Or a higher order function with Array.prototype.forEach (IE9+ if you need compat with IE)
array.forEach(function (item) {
// do something with the item
});
I am building a JavaScript array, which has strings as keys.
The array should have an object at every entry. My object looks like this (a console.log of my variable rIds):
Now, the length of this object is 0, which makes it impossible to iterate it.
I want to iterate every key, so I can retrieve and access my list of ids (rIds[key].productIds).
Code:
var rIds = [];
var response = RR.data.JSON.placements;
console.log(response);
$(response).each(function (placementId) {
var placement_name = this.placement_name;
rIds[this.placement_name] = {
productIds: []
};
$(this.recs).each(function (recIndex) {
var pid = this.pid;
pid = getRandomId(19341610, 19341746);
rIds[placement_name].productIds[recIndex] = pid;
});
});
var count = '<%=ViewBag.Get("RecommendationCount") %>';
console.log(rIds);
console.log(rIds.length);
$.each(rIds, function (index, val) {
console.log(val); // This should work as expected.
});
What did I try?
I found the following snippet, which does not work in IE8. However, this does not really help be, even though Object.keys(rIds).length results in the correct length.
for (var index = 0; index < Object.keys(rIds).length; index++) {
console.log(rIds[index]);
}
However, this code does not make my access the object.
Tl;dr & question
How do I iterate my JavaScript object which has strings as keys, so I can access the individual entries?
The Object.keys() function returns an array containing the property names of the object.
var keys = Object.keys(rIds);
for (var i = 0; i < keys.length; ++i) {
console.log(rids[keys[i]]); // object value
}
Alternatively, you can use the .forEach() method:
Object.keys(rIds).forEach(function(key) {
console.log(this[key]);
}, rIds);
Finally there's the venerable for ... in loop:
for (var key in rIds) {
if (rIds.hasOwnProperty(key))
console.log(rIds[key]);
To support versions of IE before IE9 you're kind-of stuck with for ... in, though you can find mostly-correct "polyfills" for Object.keys() and Array.prototype.forEach() at MDN.
To supplement Pointy's answer, you can also use jQuery's $.each (since you're already using jQuery elsewhere) to iterate over each key/value pair in your rIds object:
$.each(rIds, function(key, value) {
console.log(value);
});
I have a multiple select list item with id "genres". In my code, I get the value of "genres", split it, and then iterate through and adds each value to another array. But for some reason, it's adding an extra entry. Here's my code:
if ($("#genres").val()!=null) {
var genres = $("#genres").val().toString().split(",");
for (var i in genres) {
model.TitleGenres.push({ GenreId: genres[i] });
}
}
The variable model.TitleGenres is initialized as [];
When I debug this in Firebug, the values I get are:
genres: [ "6", "1770" ]
At the end of the loop, I get:
model.TitleGenres: [Object { GenreId="6"}, Object { GenreId="1770"}, Object { GenreId=function()}]
I have no idea why there is an extra entry with GenreId=function(), can anybody explain why that is and how to eliminate it?
Do not iterate over (numerical indexed) arrays in JS with for in.
Use for (var i = 0, len = array.length; i < len; i++) { ... }
Its cause you iterate over an array with 'for in' and not foreach or simpley for. With for in you iterate over all members of the array object, or in this case jquery object. It seems that one of them is a function. Use genres.each() instead.
How about this:
var x = [];
$('#genres option:selected').each( function() { x.push($(this).val()) } );
Now "x" will hold all the selected values.
I'm somehow confused:
I have a list of commands like this:
var commands = [{"command": "read"}, {"command": "write"}, {"command": "login"}];
If I try it access one of the commands like this it works:
console.log(commands[0]["command"]); // Output is "read"
console.log(commands[0].command); // Output is "read"
But if I try this the output is always undefined:
for(command in commands)
console.log(command["command"]); // undefined, undefined, undefined
for does an array iteration in javascript, so you want:
for(command in commands)
console.log(commands[command]["command"]);
ie, the command variable in your example is an array index, not the enumerated item from the array.
The for ... in construct iterates over the keys of the objects in the array, not the objects themselves. So you would need to write:
for(index in commands)
console.log(commands[index]["command"]);
The for (.. in ..) construct is for looping over objects, not arrays. Since you have an array of objects, you should be doing:
for (var i = 0, j = commands.length; i < j; i += 1) {
console.log(commands[i].command);
}
For a thorough explanation as to why you should use this for construct instead of the for...in, see answer #3010848.
Why use for..in with an array? Just access by index, and you also avoid potential problems of prototype extensions (see hasOwnProperty)
var i,len=commands.length;
for (i=0;i<len;i++ ) {
console.log commands[i].command
}
If order does not matter, more concisely
for (i=commands.length-1;i>=0;i-- ) {
}
Or
var i=commands.length;
while (i--) {
...
}
Use it like this
for(var x in commands)
console.log(commands[x].command);
Have you tried:
for(command in commands[0]) {
console.log(command["command"]);
}
Let me explain in detail. I have below an object with me -
{
"OBJECT1" : {
"NAME1" : "VALUE1",
"NAME2" : "VALUE2",
"NAME3" : "VALUE3"
},
"OBJECT2" : {
"NAME4" : "VALUE4",
"NAME5" : "VALUE5"
}
}
From this object, I want to get something like number of elements in OBJECT1 = 3 and number of elements in OBJECT2 = 2. If at all this is possible using javascript.
Basically what I am trying to do is, to loop through the name value pairs available in the object dynamically so that if someone adds another element to object, I don't have to change my code.
Also any alternative is also ruled out since I am allowed to only use object in my use-case.
Without converting your object you could iterate through the object counting properties like so:
function countObjectProperties(obj)
{
var count = 0;
for(var i in obj)
if(obj.hasOwnProperty(i))
count++;
return count;
}
Expanding on why you need to use hasOwnProperty as I said in the comment below you can run into an issue where a library or browser has added methods and properties to Objects, in order to avoid counting these we check for hasOwnProperty before counting it. More details at MSDN or at Mozilla Developer Center
For JSON string that represent an object (which is your case), you cannot use any length property. you need to loop through the object (see Kristoffer S Hansen's answer).
If it represented an array, you could get the length with:
var len = arr.length;
JQuery makes it simpler:
var len = $(JSON).length;
To answer your broader goal, as specified in your question:
For looping through the properties, you can use the for..in construct:
for (var item in myobject) {
// some browsers add more properties to every object, we don't want those
if (myobject.hasOwnProperty(item)) {
do_something(item);
}
}
Assuming that myobject is the object in your question, this will loop through it and call do_something(OBJECT1) and do_something(OBJECT2); you can use the same construct to loop through the child objects:
// loop through OBJECT1 and OBJECT2
for (var item in myobject) {
// some browsers add more properties to every object, we don't want those
if (myobject.hasOwnProperty(item)) {
// loop through the item's children
for (var pair in item) {
if (item.hasOwnProperty(pair)) {
// each of the name:value pairs will be passed to this
do_something_else(item,pair);
}
}
}
}