JS loop through objects - javascript

First I am sorry because this possibly will be very simple. But I work a lot in PHP, but that syntax won't work in JS.
I've got the following pieces of code:
var rangeArr = [];
// This piece is inside an loop of adding elements...
rangeArr[row_id] = {"row_x": row_x, "row_y": row_y, "row_name": row_name, "row_dir": row_dir, "row_length": row_length, "row_height": row_height};
row_id++;
I'll get this object for instance (got from Chrome console):
rangeArr
[undefined × 1,
Object
row_dir: "lr"
row_height: "6"
row_length: "5"
row_name: ""
row_x: 45
row_y: 71
__proto__: Object
,
Object
row_dir: "lr"
row_height: "6"
row_length: "6"
row_name: ""
row_x: 95
row_y: 208
__proto__: Object
]
I'm using the following piece of code to loop through the object array:
for (var item in rangeArr) {
if(typeof(item) !== 'undefined'){
console.log(item.row_x);
}
}
But I only get undefined errors... When I look into the console log, the whole item contains only the row_id. That means that only the index is retrieved, not the object itself.
As I said before, I have got little to no knowledge about JS Objects, but I thought that this was the right way to do this.
So how can I get my piece of code working so that I can receive the data when needed?

In your for in loop, item is actually the array key, not the array element value. To get the object, use rangeArr[item].
for (var item in rangeArr) {
var obj = rangeArr[item];
if(typeof(obj) !== 'undefined'){
console.log(obj.row_x);
}
}
That said, for in loops are a bad idea on arrays. A basic incremental for loop, or a forEach is preferred. Refer to this question for more info.
It looks like you're generating the incremental keys manually. Instead of that, you might prefer to use Array.prototype.push():
rangeArr.push({"row_x": row_x, "row_y": row_y, "row_name": row_name, "row_dir": row_dir, "row_length": row_length, "row_height": row_height});

Related

Iterating through Objects of Objects Javascript?

I have this object structure that I want to iterate through to make a node of all the "properties." So I want to make nodes for the objects 1,2,5, and 8 but not for the arrays. I have this piece of code and was wondering why Object.keys() for each of response's properties is [0] instead of [2,5] or [9,12]?
const response = {
'1':{
'2':['3','4'],
'5':['6','7']
},
'8':{
'9':['10','11'],
'12':['13','14']
},
};
for(const property in response){
if(!response.hasOwnProperty(property)) continue;
console.log(property) // prints 1 and 8
g.addNode(property);
console.log(Object.keys(property)) // [0] instead of [2,5] or [9,12]
for(const prop in property){
if(!property.hasOwnProperty(prop) || prop === 0) continue;
console.log(prop)
g.addEdge(prop,property, {directed:true})
}
}
EDIT: this loop works :)
for(const property in resp){
g.addNode(property);
for(const prop in resp[property]){
g.addEdge(property,prop, {directed:true})
}
}
I've run into this exact issue with dictionaries, and it's good you're running into this issue relatively quickly because it can get pretty hard to debug once you get further. Basically, you're iterating over a dictionary with a for..in loop, which doesn't exactly do what you want it to. Basically, each item you iterate over (property in this case) isn't the value of the dictionary ({'2':['3','4'], '5':['6','7']}), it's a full dictionary item that includes both key and value. This is practically useless to you, so it's not particularly helpful. There are a couple things you can do, one of which still uses a forEach, except somewhat differently:
Object.keys(response).forEach(function(key) {
// do your actions here
// key is your dictionary key (1, 8)
// response[key] will have your value ({'2':['3','4'], '5':['6','7']})
});
This should work, and you can put the rest of your code to use this.

Node.JS behaves strange

I have a variable called uids
var uids = [];
Then I write some value to it property
uids[16778923] = "3fd6335d-b0e4-4d77-b304-d30c651ed509"
But before it
if (!uids[user.id]) {
uids[user.id] = generateKey(user);
}
This thing behaves ok. If I try to get the value of it property
uids[currentUser.id]
It will give me a value of this property. If I try to call some methods like
Object.keys(uids);
It will give me, what I expected. And here the mystery comes...
uids;
RAM rest in piece. See the node eating ram
I am very confused now. What's wrong?
This is because you are creating a huge array and node will reserve memory for it - who knows what comes. I'd say that's a scenario where you would use a Map (or a plain object, but Map feels better here.
var uids = new Map();
var key = 456464564564654;
if (! uids.has(key)) {
uids.set(key, generateKey(user))
}
You are creating an empty array (length is zero), then you assign some value to an arbitrary index. This will make the array grow as big as the index and assign the value to that index. Look at this example using node.js REPL:
> var a = []
undefined
> a[5] = "something"
'something'
> a
[ , , , , , 'something' ]
> a.length
6
Instead of creating an array, you could create a Map() or an common javascript object (singleton). Javascript objects behave like Maps but only Strings can be used as keys. If you assign a Number to be key, javascript will convert it to String automatically.
Personally, I would go with objects because they perform better. Instantiating an object takes longer than instantiating a Map (and it doesn't seem like you need to create several groups of "uids"), but once done, adding new keys and retrieving values from any key in faster when using common objects. At least that's how things go in my node.js v6.7.0 on ubuntu 14.04 but you could try for yourself. And it would also make the least alteration to your code.
var uids = {} // common/ordinary empty javascript object instead of array.
if (!uids[user.id]) { // getting value from one key works the same.
uids[user.id] = generateKey(user) // assignment works the same.
}
////
uids[16778923] = "3fd6335d-b0e4-4d77-b304-d30c651ed509" // key will be "16778923".
uids[16778923] // getting value for key "16778923" can be done using 16778923 instead of "16778923".
////
uids[currentUser.id] // still returning values like this.
Object.keys(uids) // still returning an array of keys like this. but they are all Strings.

Can't get JSON to output

First try at using JSON. I have an ajax/php function that returns a JSON object. Back on the js side, I can see the object and output it to a div. It looks fine. I can print it to the console, still looks good. But when I try to iterate over it and expose the individual values, I just get 'undefined' in my console. I can't figure out what I am missing. Sorry it if's something obvious, but I don't see it. Thanks!
var jsonObj = JSON.parse(xmlhttp.responseText);
console.log(jsonObj); //<--looks perfect
console.log(jsonObj.length);
document.getElementById("rightsidebox").innerHTML=response; //<--looks good
for (var group in jsonObj) {
//each of these generates 'undefined' WHY???
//I get 4 'undefined' outputs for each group, so I know that my loop is iterating correctly
console.log(group.id);
console.log(group.day);
console.log(group.time);
console.log(group.name);
}
EDIT: Here is an example of one of the JSON objects being returned by my ajax call. In this example, I only have a single object inside of the array. Of course, there will typically be multiple objects:
[{"id":"7","day":"Thursday","time":"7:00 a.m.","name":"Sub 10:00"}]
EDIT 2: Given this array, I have to ask what the point of JSON is. I can return this array without having PHP encode it in JSON format. So, if all that comes back is just a javascript array, then what have I accomplished? Why not skip the JSON encoding in PHP and then iterate over the array? Clearly there is a reason for this, so I'm obviously missing something. Is there a better way to do what I am trying to accomplish? Thanks!
Consider the following:
var myJson = '{"groupA": {"id": 123, "name": "foo"}}';
var myObj = JSON.parse(myJson);
for (var i in myObj) {
console.log(i);
console.log(i.id);
console.log(myObj[i].id);
}
The expected output here is:
myGroup
undefined
123
This is because you loop is just assigning the 'key' of your object to the value i. If you were to iterate an array, instead of an object, you'd get indices instead of strings.
In the example JSON you've given, you have an array with one object in it. If you intend to have multiple objects in your array, something like this would be better:
for (var group in jsonObj) {
var thisGroup = jsonObj[group];
thisGroup.id; // Etc etc..
}
If you have the correct jsonObj, and you say that you do, you can use formatting to output the object in an easy to read form. You don't have to loop through it.
console.log(JSON.stringify(jsonObj, null, 1));
Not sure why this works, when my original for (var group in jsonObj) loop doesn't, but whatever...
for (var i=0; i < jsonObj.length; i++) {
console.log(jsonObj[i].id);
console.log(jsonObj[i].day);
console.log(jsonObj[i].time);
console.log(jsonObj[i].name);
}

Checking value exists in an array position

I have a large array called "data".
At the 10th array position i have this at its data value:
[10] => 1,2
Now what im trying to do in JS is something like this:
i = 1;
if(i in data[10]){
//great success, very nice!
}
I thought comma separated data might act like an array with the "IN" method, but its not working. I get this error:
Uncaught TypeError: Cannot use 'in' operator to search for '1' in 1,2
What would be the correct solution for my problem ?
You don't show the code for how you assign 1,2 to data[10]. The value of 1,2 is simply 2 as you can see from executing the following in a JavaScript shell/console. See the reference for how the comma operator works.
However, the error message you are getting suggests that you have the string"1,2". To turn it into an array, you should use split() as in:
> data[10] = "1,2"
1,2
> data[10].split(',')
[ "1", "2" ]
To iterate over the values you can use the in operator on the resulting Array as in:
var data = new Array();
data[10] = '1,2';
var valueArray = data[10].split(',');
for (var i in valueArray) {
alert('valueArray[' + i + '] is ' + valueArray[i]);
}
You can run this in a browser console and the alert will show you two messages:
valueArray[0] is 1
valueArray[1] is 2
Note that you don't need to initialize i before the loop begins. The inoperator will do this automatically. Also, it's good practice to use local variables hence the var i in the code above.
On a side note, if you are new to JS but you need to deal with a lot of data structure manipulation, it's worth learning about underscore.js. Take a look at _.each() in particular. Underscore can save you from writing a lot of looping logic.
If, however, you want to do a membership check then you need to use not in but Array.indexOf(). See http://jsfiddle.net/nRS9m for an example forked from your jsfiddle in the comments. More examples:
> valueArray
[ "1", "2" ]
> valueArray.indexOf("3")
-1
> valueArray.indexOf("1")
0
> valueArray.indexOf("2")
1
> valueArray.indexOf(1)
-1
> valueArray.indexOf((1).toString())
0

Array containing objects has wrong length

I have an array like:
errors = [ {...}, {...}, {...} ]
It's an instanceof array, yet it only returns 1 for .length?
Relevant code:
if(data.error){
errors.push({'element':ele,error:data.error});
}
//Above is looped a few times and there are N number of errors now inside
console.log(errors) //Returns 2+ objects like {...}, {...}
console.log(errors.length) //Returns 1
For Uzi and Muirbot, here's the errors array:
[
Object
element: b.fn.b.init[1]
error: "You must enter "example" into the field to pass"
__proto__: Object
,
Object
element: b.fn.b.init[1]
error: "Crap!"
__proto__: Object
It is correct, this code:
var errors = new Array();
errors.push({'element':'ele', error:'data.error'});
...adds ONE object to the array. The object has two properties.
It's possible your code is executing in an order other than what you're expecting. ie, when you log both errors and errors.length, errors does contain only 1 object. But after that you are adding to the errors array, and only after that are you looking at the console. At that point you could see a larger array in errors for two reasons - first, your actual code isn't logging errors but some object that contains errors. In that case the console display is live, and will show you not what was in errors at the time, but what is in it now. Alternatively, the console could just be taking some time to log errors.
Without more code I can't be sure if this is the case. But you could verify it by replacing console.log(errors); with console.log(errors[1]);. If errors is really only 1 long at the time, it will log undefined.
The problem was that Chrome's Web Inspector's console.log is an async event. So, the length was a property lookup so it gave that back instantly, but the object with two items inside was held off until the rest of the events had fired.
In the future I, and others with this issue, should use debugger; instead.
is it an Array object or something that resembles it?
arrays do work:
> a = [{a:1}, {b:2}]
[Object, Object]
> a.length
2
you'll have to provide more code.
and now that you've provided the relevant code, the correct answer is what Steve Wellens said (which was downvoted, by the way).
Array.push adds a single element, objects may have more than one key but they're still a single object so your real case was different from your original example, which of course works.
another possibility:
> a = []
[]
> a.length = 2
2
> a
[]
> a.length
2
> a instanceof Array
true

Categories

Resources