my code works and no idea why (working with objects) - javascript

I had the following object:
var dataset = [
[
{"value":"PRE","formattedValue":"PRE"},
{"value":"2017-06-15 00:00:00","formattedValue":"15/06/2017 0:00:00"},
{"value":"COSTA RICA","formattedValue":"COSTA RICA"},
{"value":"6.15","formattedValue":"6,150"}
],
[
{"value":"PRE","formattedValue":"PRE"},
{"value":"2017-06-15 00:00:00","formattedValue":"15/06/2017 0:00:00"},
{"value":"EL SALVADOR","formattedValue":"EL SALVADOR"}
]
]
Its too complex and has data I don't actually need, so I tried to turn it into this:
[
{
"estado": "PRE",
"fecha": "2017-06-15 00:00:00",
"pais": "COSTA RICA",
"precio": "6.15",
}
]
I finally did it, but I'n unsure why my code works.
I done it with this code:
var datafinal = [];
function convertion(){
var dataobj = dataset.getData();
for(var x in dataobj){
datafinal[x] = { "estado": dataobj[x][0]["value"] };
datafinal[x]["fecha"] = dataobj[x][1]["value"];
datafinal[x]["pais"] = dataobj[x][2]["value"];
datafinal[x]["precio"] = dataobj[x][3]["value"];
}
}
If you pay attention, you'll see the first value i add to the new object is using a different format to get added than the rest.
I discovered that if i add every value with the second format it adds nothing.
But if i add everything in the first format, it only adds the last value;
So, i made the vale in the first format, and the rest in the second format, and it worked just fine.
...why though, can someone explain to me why is this happening?

This is because at first datafinal[x] does not yet exist, so you need to give it a value, i.e. assign it an object. That is what the first assignment does. The other assignments are mutating the existing value, since you don't want them to replace the value you assigned in the first line.
Notice the other assignments don't assign to datafinal[x] itself, but write to a property of it: so you extend the object that you assigned in the first assignment.
In fact, the first assignment could be broken into two parts:
datafinal[x] = {};
datafinal[x].estado = dataobj[x][0].value;
... and so now all property assignments could look the same (NB: you don't need the square bracket notation for these literal property names). The first assignment is now just initialising the value as an object (as opposed to a number, a string, a boolean...). Without such assignment, you don't have an object, and cannot assign properties to it.
You could maybe make it easier to understand if you would write it in one object literal assignment:
datafinal[x] = {
estado: dataobj[x][0].value,
fecha: dataobj[x][1].value,
pais: dataobj[x][2].value,
precio: dataobj[x][3].value
};

In the current form you are initialling telling it to create an object at that position and 'initialising' it with a value of { "estado": dataobj[x][0]["value"] };.
Subsequent attempts to access the object datafinal[x] then access a property of that object and as that property does not yet exist, creates it with your given value.
By simple repeating the line datafinal[x] = { "estado": dataobj[x][0]["value"] }; as you suggest with the different keys and values, you are merely overwriting
the value of datafinal[x] with a new object each time.
EDIT:
As for why only adding the values in your second format does not work, this is down to the fact that in doing so you are trying to access properties of an object datafinal[x] that does not yet exist. Whereas, by doing one call in your first format creates that object.

If you use your first format it will rewrite all your object everytime you call it
datafinal[x] = { "estado": dataobj[x][0]["value"] };
means that datafinal[x] is equal to that so if you do
datafinal[x] = { "fecha" = dataobj[x][1]["value"] };
it will erase what's in datafinal[x]
that is why your first format doesn't work

Related

How to get a JSON object's key from the object itself in JavaScript/a Vue v-for loop?

I'm not looking for the keys that this object contains but the key of the object itself (the key in the array containing the object).
I have this JSON:
{
"Object name (text)": {
"raw": "Some more text.",
},
"Another name": {
"raw": "Some other text.",
}
}
and would like to get "Object name (text)" for the first item.
My Vue code is:
<CustomComponent
v-for="object in objects"
:key="getKey(object)"
:object="object"
/>
I'm not sure if the getKey-method approach is how one is intended to get unique identifiers for iterating through the JSON array. Its code currently is:
getKey(object) {
return Object.keys(object)[0];
}
Now I'd like to somehow pass the name of the object to the CustomComponent ("Object name (text)" in the first case).
One temporary workaround that I intended to use until I find something more appropriate was getting the keys from the objects array like so:
:objectName="getObjectName(object)" and itemNumber: -1 in data and this method:
getObjectName(object) {
this.itemNumber = this.itemNumber + 1;
var objectName = Object.keys(this.objects)[this.itemNumber];
console.log("Object name: ", objectName);
}
However, the first line of this method causes it to run hundreds of times instead of only two times (why is that?; it works in the first 2 executions of the method and when commenting out that line) and I think this is unlikely the proper method to simply retrieve the object's name/key.
It also didn't work when putting the above code into the getKey method which would make more sense (and I had the code in that method before creating a separate method to debug). Then the key could be accessed in the component with this.$vnode.key However, it keeps being undefined. This might be a separate problem even though it could resolve this problem here as well - I might create a new question for it. It enters the methods "getKey" and "getObjectName" 6 times each even though it only renders two items on the page, like it should.
-> How to get the JSON object's key in JavaScript?
(Preferably from the object itself after iterating through a JSON array with a loop with Vue instead of only indirectly by checking the objects array.)
Edit: as a workaround I have now done this:
var keys = Object.keys(this.objects);
keys.forEach(element => {
this.objectsWithKeys.push({
object: this.objects[element],
key: element
});
});
<CustomComponent
v-for="objectWithKeys in objectsWithKeys"
:key="objectWithKeys.key"
:object="objectWithKeys.object"
>
</CustomComponent>
this.$vnode.key
This is solved, I used var objectsWithKeys = data[Object.keys(data)]; and {{ $vnode.key }}.

JavaScript Array Issue with data['sax']

I have a confusion of what this array can hold. Also, I want to know how it assigns the values to the variable set.
Can someone give me an example of data['sax'] please and explain me the loop below?
for(var x = 0; x < data['sax'].length; x++){
var set = data['sax'][x];
Then what does this mean ?
id : set.saxID,
name : set.symbol
What you have here is an array that is being looped through. data['sax'] will be something along the lines of the following:
var data = {
sax: [
{
saxID: 1,
symbol: 1
},
{
saxID: 2,
symbol: 2
}
]
}
As you can see in the example above, sax is an array which contains multiple objects. What happens when you loop over it, is that it accesses one of the objects inside the array. So data['sax'][0] will give you the object with saxID: 1.
Using the variable set to temporarily store the data in; you can access the data of data['sax'][0] as set. So data['sax'][0].saxID becomes set.saxID. It is somewhat of a shorthand version of accessing the data.
What happens with id: set.saxID, is that the values get assigned to a new object. Which will be something like the following.
var newSax = {
id: set.saxID
}
You are basically transferring data from one object to another.
Explaining the code
var set = data['sax'][x];
Here you are creating a variable called set and assigning it a value from data['sax'][x].
data['sax'] this might look like a array But Its Not, to access value of a array we use index but here its a string. This is another way of accessig a property value of a object. So data is a object with one of its property being sax. That means
data = {sax: somevalue};
Now we have,
data['sax'][x] So as you know data['sax'] is a object and then this [x] , here x is not a string its a variable and it holds the Number value (0,1,2,3...) , it means your data['sax'] value is a array since we are accessing from index.
So from the above analysis your data['sax'] will be in this format.
Array
data = { sax : ["someValue","someValue"]}
So variable set will be
var set = "someValue"; // if x = 0, as in the first loop
Now coming to the code
id : set.saxID,
name : set.symbol
set.saxID this is used if the set is an object. In Jquery to retrieve the value of a property in the object you use the . operator with property name (or by the property name as seen above). So the code means set is a object with two properties saxID and symbol. So your set object will be like
set = { saxID: 123, symbol = "TEST"}
That also means that your data value be
data = { sax : [{saxID: 123, symbol = "TEST"},{saxID: 123, symbol = "TEST"}]}
Let me know if I was clear

Eloquent Javascript: Uncaught TypeError: Cannot read property 'indexOf' of undefined

I am learning JavaScript based on Eloquent Javascript and during one of the chapters, came across this error. Not sure what I am doing wrong here. I am getting an error "Cannot read property 'indexOf' of undefined" against the code return journal.events.indexOf(event) != -1
Also, can someone explain how that line works? Isn't IndexOf supposed to return the first position of occurrence of the specified value (in this case, event)? But I see in the book that the line return journal.events.indexOf(event) != -1; returns either true or false.
var journal = [];
function addEntry(events, didITurnIntoASquirrel) {
journal.push({
events: events,
squirrel: didITurnIntoASquirrel
});
}
addEntry(["work", "touched tree", "pizza", "running",
"television"], false);
addEntry(["work", "ice cream", "cauliflower", "lasagna",
"touched tree", "brushed teeth"], false);
addEntry(["weekend", "cycling", "break", "peanuts",
"beer"], true);
function hasEvent(event, entry) {
return entry.events.indexOf(event) != -1;
}
console.log(hasEvent("pizza", journal));
In your sample code journal is an array
var journal = []; <--- Array
Therefore events should be accessed with an index like:
journal[0].events.indexOf(event)
^
|
|
Here you need to find the right index to get your events
I'm unsure how far along you are with learning javascript, so forgive me if some of this sounds condescending or obvious.
Let's break this down one step at a time. You begin with an empty array.
var journal = [];
console.log(journal); //[]
//it's defined. It's an empty Array.
By calling push on an array, you add something to the end of the array.
More on Array.push.
I don't like this example for beginners because it expects you to know already that you can define an object while you're passing it as an argument. This is done this way because you don't truly need a variable reference to an object that's only used once and is therefore a good way of reducing bloat in code. But verbosity is much better when teaching someone, imho.
//Wait, what am I pushing into the journal array?
journal.push({
events: events,
squirrel: didITurnIntoASquirrel
});
This should make more sense:
Create an object first. Then add that object to the "journal" array.
function addEntry(events, didITurnIntoASquirrel) {
var temporaryObject = {
events: events,
squirrel: didITurnIntoASquirrel
};
journal.push(temporaryObject);
}
Now journal is an array with an unnamed object at its first index.
1. console.log(journal); // [temporaryObject]
2. console.log(journal[0]); - //temporaryObject
The visibile difference is the lack of parens, but the difference is important.
On line 1 you have the array itself, on line 2 you have what's inside it (i.e. the object). You need to get the object (via the technique on line 2) before you can access properties of that object, such as "events" or "squirrel". Moving on.
addEntry(["work", "touched tree", "pizza", "running", "television"], false);
Next, we invoke the addEntry function. Same confusion here. I've rewritten it slightly to make the arguments more understandable.
var entry = ["work", "touched tree", "pizza", "running", "television"];
addEntry(entry, false);
//repeat 2 more times with different data
So first we define an array, then we pass it to the addEntry function. when the addEntry function runs (it will run right when we invoke it), the "entry" argument will be represented function as the "events" parameter (simple way: events = entry and didITurnIntoASquirrel = false). some notes on parameters vs arguments.
So you should be able to understand now that you're passing an array and a boolean to the addEntry function. That function creates an object based on those values referencing them via their parameters. That object is then added to the journal array.
What you end up with is 4 levels of depth. You have an array called journal, which has objects in it. Those objects have a property called events, which is a different array. That array has several strings inside it. To access the events array and use indexOf to see if it has a given string in it, you need to traverse that depth one level at a time.
//journal is the array, journal[0] is the object, journal[0].events is the property of that object
console.log(journal[0].events) //["work", "touched tree", "pizza", "running", "television"].
Note this is the same data that we originally put in the entry variable. This may seem unnecessarily complicated, but trust me when I say this type of structure is useful in real life when you need to manage data hierarchy or other logical relationships between "things" in Object Oriented programming.
Now, all the work we've done so far is to add to the journal array. We now want a function to see what's inside it. Why a function? So you don't have to rewrite the same code over and over.
function hasEvent(event, journal) {
return journal.events.indexOf(event) != -1;
}
By now I hope you can spot the error in this function. journal.events doesn't work, because journal is an array, not an object (you skipped a level, and your computer isn't smart enough to know what you mean) journal[0].events would work, because you are telling javascript ("from the journal array, I want the object in the first slot, and the events property of that object").
The simplest fix is to send journal[0] to the hasEvent function instead of journal. Beware, this will only check journals first index. Realistically you'd want a for loop inside the hasEvent function or wrapping the call to that function to check all indexes. For now we will hardcode them, since we know there are 3, but its not a good idea in real life, since later there may be more than 3 entries in the journal).
This funciton is returning the result of calling indexOf() (some number or -1) with -1. Let's again rewrite it so that it makes more sense.
New hasEvent function:
//I renamed the variable so it makes more sense what it really is. It's the object, not the journal array.
function hasEvent(event, journalEntry) {
var index = journalEntry.events.indexOf(event);
var result = (index != -1); //true if it was found, false if it wasn't found.
return result; //a boolean based on the above comparison.
}
//Ack! My kingdom for a "for loop". Don't worry about that right now.
console.log(hasEvent("pizza", journal[0]));
console.log(hasEvent("pizza", journal[1]));
console.log(hasEvent("pizza", journal[2]));
TL;DR
Here is a fiddle with working code:
http://jsfiddle.net/o8dg1ts6/1/
To answer your 2nd question:
"Isn't IndexOf supposed to return the first position of occurrence of the specified value"
Yes, and indexOf returns -1 if if the value is not found in the array.
So if the event is found, then the expression indexOf(event) != -1 will evaluate to true.

Retrieving JS' Object value without knowing it's name

This is a fairly common question here in SO, and I've looked into quite a few of them before deciding to ask this question.
I have a function, hereby called CheckObjectConsistency which receives a single parameter, an object of the following syntax:
objEntry:
{
objCheck: anotherObject,
properties: [
{
//PropertyValue: (integer,string,double,whatever), //this won't work.
PropertyName: string,
ifDefined: function,
ifUndefined: function
}
,...
]
}
What this function does is... considering the given parameter is correctly designed, it gets the objCheck contained within it (var chk = objEntry.objCheck;), It then procedes to check if it contains the properties contained in this collection.
Like this
for(x=0;x<=properties.length;x++){
if(objCheck.hasOwnProperty(properties[x].PropertyName)){
properties[x].ifDefined();
}
else{
properties[x].ifUndefined();
}
What I want is... I want to bring it to yet another level of dynamicity: Given the propositions that IfDefined and IfUndefined are functions to be called, respectively, if the currently-pointed PropertyName exists, and otherwise, I want to call these functions while providing them, as parameters, the very objCheck.PropertyName's value, so that it can be treated before returning to the user.
I'll give a usage example:
I will feed this function an object I received from an external provider (say, a foreign JSON-returning-WebService) from which I know a few properties that may or may not be defined.
For example, this object can be either:
var userData1 = {
userID : 1
userName: "JoffreyBaratheon",
cargo: "King",
age: 12,
motherID : 2,
//fatherID: 5,--Not defined
Status: Alive
}
or
var userData2 = {
userID :
userName: "Gendry",
cargo: "Forger Apprentice",
//age: 35, -- Not Defined
//motherID: 4,-- Not Defined
fatherID: 3,
Status: Alive
}
My function will receive:
var objEntry=
{
objCheck: userData1,
properties: [
{
PropertyName: "age",
ifDefined: function(val){alert("He/she has an age defined, it's "+val+" !");},
ifUndefined: function(){alert("He/she does not have an age defined, so we're assuming 20.");},
},
{
PropertyName: "fatherID",
ifDefined: function(val){alert("He/she has a known father, his ID is "+val+" !");},
ifUndefined: function(){alert("Oh, phooey, we don't (blink!blink!) know who his father is!");},
}
]
}
CheckObjectConsistency(objEntry); // Will alert twice, saying that Joffrey's age is 12, and that his father is supposedly unknown.
ifDefined will only actually work if, instead of properties[x].ifDefined();, I somehow provide it with properties[x].ifDefined(PropertyValue);. And here, at last, lies my question.
Being inside the consistency-checking-function, I only know a given property's name if it's provided. Being inside it, I can't simply call it's value, since there is no such function as properties[x].ifUndefined(properties[x].GetValueFromProperty(properties[x].PropertyName)) ,... is there?
I'm sorry. Not being a native english speaker (I'm brazilian), I can't properly express my doubts in a short way, so I prefer to take my time writing a long text, in an (hopefully not wasted) attempt to make it clearer.
If, even so, my doubt is unclear, please let me know.
I think you're looking for the bracket notation here. It allows you to provide an arbitrary value as key to access the object. Also, you know its name. You have your properties object right?
objEntry.properties.forEach(function(property){
// Check if objCheck has a property with name given by PropertyName
if(!objEntry.objCheck.hasOwnProperty(property.PropertyName)){
// If it doesn't, call isUndefined
property.isUndefined();
} else {
// If it does, call isDefined and passing it the value
// Note the bracket notation, allowing us to provide an arbitrary key
// provided by a variable value to access objCheck which in this case is
// the value of PropertyName
property.isDefined(objEntry.objCheck[property.PropertyName]);
}
});
Oh yeah, forEach is a method of arrays which allows you to loop over them. You can still do the same with regular loops though.

Add value to json root dynamically

Well, I'm so confused. I have made a json element like this:
var world = {"county": []};
world.county.push({name: "America", flag: "yes", countries: []});
world.county[0].countries.push({name: "Costa Rica", capital: "San Jose"});
This leads me to think two things:
I'm mixing arrays with json objects. How can I avoid using arrays in this scenario?
How can I add elements to the json root dynamically?
Regarding question 2, I'm facing issues because I don't know how to add elements to the root, let's say that I have tried this, but it doesn't work:
var index = 0;
var word = {};
world.index.push({name: WA});
So, by this way I could add elements iterating some array created previously.
First, let's get this out of the way: it's only JSON if it's a string representing a JavaScript object. What you have there is an object literal.
Now, as for your question, you can add elements to an object simply by using:
object.newProperty = value;
As for your wanting to avoid arrays, just use arrays. They are the correct type of object to use, and you shouldn't use anything else for that task.
Start with Kolink's answer. Then, for what you are doing here:
var index = 0;
var world = {};
world.index.push({name: "WA"});
It looks like you are trying to add a property to world with the index 0. Given you are then trying to use .push() it would seem you want that property to be an array, in which case you would do that like this:
world[index] = [];
world[index].push({name: "WA"});
Given that world started as an empty object that would create this structure:
{ "0" : [ {name:"WA"} ] }
In a general sense, to access an object property where the property is in a variable you use the [] array-style syntax. So:
world["somePropName"]
// does the same thing as
world.somePropName
// so with a variable:
var x = "somePropName";
world[x]

Categories

Resources