Json parent value with nested children - javascript

I want to create a Json object (in javascript) with multible childeren. But the parent must also have a value, so the code can be executed as:
var parent = {
"child": {
"ownValue": "valueChild",
"grandchild": "ValueGrandChild",
}
};
parent.child.grandchild // return "valueGrandChild"
parent.child // return "valueChild"
Is this possible in javascript?

If I understand your question (I'm not sure), I would use a different strategy to solve your problem.
As you know, json objects does not have attributes but just children properties. You can use a properties called child to store the children objects (the subtree) of your parent object.
var parent = {
"value": "Parent own value",
"child": {
"grandchild": {"value": "ValueGrandChild", "child": {}}
"anotherchild": {"value": "anotherChildValue", "child": {}}
}
};
Children and attributes are better separated and you can address them (and the "proper" object properties) as below:
parent.child.grandchild.value // returns "valueGrandChild"
parent.value // returns "Parent own value"
You can have also some other commodities:
var how_many_child = Object.keys(parent.child).length
var a_child = parent.child.anotherchild
var how_many_nephew = Object.keys(a_child.child).length
a_chid.value; // returns "anotherChildValue"
parent.child.anotherchild.value; // returns "anotherChildValue"

Not sure if I understand the question, but you have an error in your formatting of the object at least. It works the way you want if you change the ";" to a ",". (Look below)
Change it from;
var parent = {
"child": {
"ownValue": "valueChild";
"grandchild": "ValueGrandChild";
}
};
to;
var parent = {
"child": {
"ownValue": "valueChild",
"grandchild": "ValueGrandChild",
}
};
That was you can get the valueChild by using;
parent.child.ownValue

Even if you did get an object to return another value, you would no longer be able to use that object normally. Every reference to the object would only be referencing the value (invalidating nested object references). You could obviously just keep the "ownValue" property to use for each value you want to tie to an object though.

Related

QML Javascript Dictionary of Property Alias not Updating

My question is the following:
Do changes to the javascript dictionary values not modify the actual value that is mapped, but rather its own internal copy? Is there a way to get around this?
I have a javascript dictionary that contains property aliases of an object.
When I assign them values, the objects in the dictionary itself changes but it does not propagate outward to the actual display that I want to change.
I have had this problem before, placing the dot access outside of the dictionary access fixed it. However, I cannot do it this time around due to the fact that you cannot dot access using .text because it produces error of cannot read property of undefined.
QML: Cannot read property 'xxx' of undefined
My code resembles something of the following example, I had it obscured to protect actual info so sorry if it is a cringy example.
onUpdate passes in another dictionary that I want to tie to the local .qml dictionary.
ControllerDisplay.qml
// ...
property alias id1: id_box.text
// ...
SomeBox
{
id: id_box
text: "some text"
}
main.qml
ControllerDisplay{
id: controller
}
// ...
Connections
{
target: myguimodel
onUpdate:
{
var dict = { "ID1" : controller.id1}
for (var key in updates)
{
dict[key] = updates[key] // does NOT change the value in ControllerDisplay
controller.id1 = updates[key] // DOES change the value ControllerDisplay
}
}
}
When you do var dict = { "ID1" : controller.id1}, you store the value of controller.id1, not a reference to it.
If you want to be able to modify it you could do:
var dict = { "ID1": { "object": controller, "property": "id1"}};
for (var key in updates) {
var target = dict[key];
target.object[target.property] = updates[key];
}
This whole code doesn't look really QML idiomatic though. I would try using property binding if I were you.

Passing an unknown number of nested object properties into a function [duplicate]

This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 5 years ago.
Not sure if my title describes what I want to do correctly. Basically, I want a function that extracts properties from objects containing objects. I am going to need to loop through various arrays containing many objects of the same class and extract specific values.
myarray1[
0:
object1 = {
objectProp1: {
objectProp1Prop1:"Hello",
objectProp1Prop2:"Goodbye",
objectProp1Prop3:{
objectProp1Prop3Prop1: "Come here",
objectProp1Prop3Prop2: "Go away"
},
},
objectProp2: "Yo",
objectProp3: "Seeya",
}
1:
object2 = { same as object1 but with other property values }
];
myarray2[
0: { different type of object with a different set of nested properties that the function can extract }
1: { idem }
];
function extractProperty(objectArray, property) {
//How do I write this code?
propertyvalue = objectArray.property;
return propertyvalue;
}
extractProperty(myarray1[0], object.objectProp3) = "Seeya"
extractProperty(myarray1[0], object.objectProp1.objectProp1Prop1) = "Hello"
extractProperty(myarray1[0], object.objectProp1.objectProp1Prop3.objectProp1Prop3Prop1) = "Come here"
In the final code the function needs to be able to loop through all the array keys and create an array list containing the chosen property from every object in the original array, but that I can manage. It's the sending of the specific property that needs to be extracted from the objects in the array into the function that I have no idea how to do.
Is there a generalised way to send a "path" of properties into a function and then use it there? How?
Thanks for your help!
Looks like an assignment to me. So I won't give you the code but will explain the approach.
First you need to pass the property names as a string
In your function you need to split the string based on the delimiter, like .
Keep a reference of current object
Then iterate on all the property names that you got from #2
Fetch current property name from current object and replace current object with the returned value.
return current object at the end.
Note: you need to add some validations in between. I've skipped those for you to explore ;)
You could try recursion:
object1 = {
objectProp1: {
objectProp1Prop1:"Hello",
objectProp1Prop2:"Goodbye",
objectProp1Prop3:{
objectProp1Prop3Prop1: "Come here",
objectProp1Prop3Prop2: "Go away"
},
},
objectProp2: "Yo",
objectProp3: "Seeya",
};
object2 = {
objectProp1: 'test1',
objectProp2: 'test2'
}
var myArray = [object1, object2];
function getProp(objArray, prop) {
for(var key in objArray) {
if (key == prop)
return objArray[key];
if (typeof objArray[key] == 'object')
return getProp(objArray[key], prop);
}
}
//test
document.getElementsByTagName('h1')[0].innerHTML = getProp(myArray[0],'objectProp1Prop3Prop1');
I added a Fiddle for you to try it: https://jsfiddle.net/afabbro/vrVAP/

Compare object property to variable in localstorage in JavaScript

Is it possible to compare an object property to a variable stored in localstorage using Javascript or Jquery? Here's what I mean...
So I have an object like this:
var persons = [
{
"firstName": "Dwight",
"surName": "Stender",
"picture": "https://randomuser.me/api/portraits/med/men/99.jpg",
"id": "1"
}
]
And I have a variable stored in localstorage (the name is clickId). Now I want to compare the id from the object to that variable in localstorge. I can print them both to the console so I know they work. But when I try to compare them, it suddenly doesn't work anymore (even though the id and the variable contain the same number). This is how I compared the two:
for (i = 0; i < persons.length; i++) {
if (persons[i].id == localStorage.clickId) {
document.getElementById("result").innerHTML = "yay"
} else {
document.getElementById("result").innerHTML = "nay"
};
};
Note 1 I have also tried comparing the two with === instead of ==
Note 2 the statements to be executed inside the if...else are just placeholders for the purpose of explanation
You need to use localStorage.getItem(key) to retrieve the object you previously stored. Also note that as localStorage can only hold string you'd need to serialise the object before/after saving it. JSON would be ideal for this:
Also note that you can use some() to negate the for loop, and a ternary to simplify the if.
var persons = [{
"firstName": "Dwight",
"surName": "Stender",
"picture": "https://randomuser.me/api/portraits/med/men/99.jpg",
"id": "1"
}];
var person = JSON.parse(localStorage.getItem('person') || '{}');
document.getElementById("result").innerHTML = persons.some(p => p.id == person.clickId) ? "yay" : 'nay';
localStorage.setItem('person', JSON.stringify({
clickId: 1
}));
<div id="result"></div>
Working example
you can use the inArray method of Jquery without need to use the loop
$.inArray(value, array)
Returns index of value in array. Returns - 1 if the array does not contain the value

find if path exists in json nodejs

I would like to add to the an existing json a new value in the following path:
 
VAL:"BS", PATH:["info", "bosses", "lives"]
if my json had the passes it will add the value, otherwise I will create the fields
example:
var myJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"bosses": {"name": "sam"}}
    }
}
so my new json will look like this:
var myNewJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"bosses": {"name": "sam", "lives": "BS"}}
    }
}
an example when I didn't have the fields:
var myJson = {
    "root": {
        "name": "jim",
        "age": "4",
    }
}
the output:
var myNewJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"bosses": {"lives": "BS"}}
    }
}
an example where part of the path exists I didn't have the fields:
var myJson = {
    "root": {
        "name": "jim",
        "age": "4",
 "info": {"salary": 500}
    }
}
the output:
var myNewJson = {
    "root": {
        "name": "jim",
        "age": "4",
        "info": {"salary": 500, "bosses": {"lives": "BS"}}
    }
}
how can I check if path exists (note: part of the path might exist- how can I know from where to start it?)
This is old, but...
testing existence of fields on paths is nicer now, with optional chaining, like:
var infoExists = !!myJson?.root?.info - the ?. means that if root were missing, the line wouldn't break.
In this case though, I wouldn't worry about testing for the existence of fields, I'd use spread operators to just rebuild the info object:
var newInfo = {"bosses": {"lives": "BS"}};
var info = {...myJson.root.info, ...newInfo};
if myJson.root.info doesn't exist, no problem (as long as myJson.root does, cue an optional chaining check?), we just get the newInfo.
if myJson.root.info currently holds {"salary": 500}, the spread operators will combine that to "info":{"salary": 500, "lives": "BS"}.
if myJson.root.info currently holds the same as newInfo, well, no sweat, we end up with no change.
Now you have the info object exactly as you want it, you can simply replace it in the original object with
myJson.root.info = ...info;
The first thing you could think it works could be some code like:
if (myObject.attributeName){
//property exists!
}
It will work for you in many tests but I sure you know that javascript manage some values as truthy or falsy. It use lot's of different type value as boolean false in many comparison (just === not convert type).
When you check something as
if(somethingtotest){
// it's true
}
It is the same you'd write
if(somethingtotest == true){
// it's true
}
'==' operator tryes to convert different types to be "similar" together.
In the first example code many of object attribute values can be '==' true.
That attribute value is truthy, meaning it’s an object, a non-empty string, a non-zero number that’s not NaN, true, and not null or undefined.
That means if the attribute is an empty string (“”), this check will fail. The same if value is 0 (zero), null, false. Failing, in this case, doesn’t mean that the property doesn’t exist. In fact, the property does exist and contains a value, but the value is falsy and so doesn’t pass this test.
Since ECMAScript 5 the base Object has the function hasOwnProperty(propertyName)
So you could try
if(myObject.hasOwnPorperty('attributeName')){
// do something
}
This function remembers us that the Objects has also prototype attributes that our object could inherit. For example if I write
myObject.anyAttribute='AnyValue';
var my1stObject = Object.create(myObject);
var my2ndObject = Object.create(myObject);
myObject.anyAttribute='AnotherValue';
console.log(my1stObject.anyAttribute);
console.log(my2ndObject.anyAttribute);
last two rows will print 'AnotherAttribute'.
In this case 1st and 2nd objects have not own property anyAttribute but they will use the prototipe one.
Different if you write
myObject.anyAttribute='AnyValue';
var my1stObject = Object.create(myObject);
var my2ndObject = Object.create(myObject);
my1stObject.anyAttribute='AnotherValue';
console.log(my1stObject.anyAttribute); //AnotherValue
console.log(my2ndObject.anyAttribute); //AnyValue
First object hasOwnProperty 'anyAttribute' because we set it.
At last, to be shure to check if property, proptotipe or own, really exists, you would like to use
if('anyProperty' in myObject){
//do something
}
I suggest you to read it better at this link:
https://www.nczonline.net/blog/2010/07/27/determining-if-an-object-property-exists/

Parameter is the name of a variable instead of its value when initialising an object with a function as property

I'm trying to initialize properties of an object, one being a function.
This works if I hardcode it:
subitems = {
"1" : { "label": "Link1",
"action": function(obj) {showURL(obj,"http://link1.com")}
},
"2" : { "label": "Link2",
"action": function(obj) {showURL(obj,"http://link2.com")}
}
}
or if I try doing it dynamically using a list in a variable
subitemdata = [['Link1','http://link1.com'],['Link2','http://link2.com']];
I use this to fill the label and action properties and generate the object
subitems = {};
for (i=0; i<subitemdata.length;i++) {
subitems[i] = {};
subitems[i].label = subitemdata[i][0];
subitems[i].action = function(obj) {showURL(obj,subitemdata[i][1])};
}
I get
subitems = {
0 : { label: "Link1",
action: (function(obj) {showURL(obj,subitemdata[i][1]);})
},
1 : { label: "Link2",
action: (function(obj) {showURL(obj,subitemdata[i][1]);})
}
}
How can I write the code so that in the 'action' property the strings 'subitemdata[i][1]' don't appear in the parameter list of the function 'showURL' but the actual values from the 'subitemdata' list 'http://link1.com' and 'http://link2.com' do?
I just can't manage to recreate the hardcoded object version when using the dynamic way to initialise the object.
subitem[i].action = (function makeConstantStr(str){
//this takes the array, gets the value and returns a new function with
//the current value in the array as the 2nd argument of the innermost function
return function(obj) {showURL(obj,str)};
}(subitemdata[i][1]));
If you wrap it in an immediately invoked function and pass the value in, it should evaluate it immediately and the argument will be set to the value of the array contents instead of to the array reference itself.
Just to make sure you're clear though, as long as you don't modify subitemdata, the array reference will return the same thing when you work with it. You don't need to do this unless you want to hold onto the value of the array at that particular moment in time.

Categories

Resources