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.
Related
In the code below, I can get a reference to the text000 object, but I need to capture its child array as my target payload. Once I have a reference to the key, how can I capture its children?
Full object is below:
activeItem = [{"dnd":{"index":0,"active":true,"group":"common","label":"Text (000)","type":"text"},
"json":{"schema":{"properties":{"text000":{"title":"Text (000)","type":"string"}},"required":["text000"]},"layout":[{"key":"text000","description":"","floatLabel":"auto","validationMessages":{"required":"Required"}}]}}]
To grab a reference to the "text000" key I'm using:
const myEl = Object.keys(this.activeItem.json.schema.properties); // points to text000
I need to pull that key's contents/children > {"title":"Text (000)","type":"string"} out to use it as my target payload for this operation.
The text000 element is dynamic so I need its reference, which is why I'm using the Object.keys() method to point to it.
Feel free to school me on the proper names to use to refer to these elements. For example, not sure exactly how to reference > {"title":"Text (000)","type":"string"} with respect to the key text000. Is that the key's "children", "value", "contents" or what?
UPDATE:
console.log('TRY: ', this.activeItem.json.schema.properties[0]);
// Returns undefined
console.log('TRY2: ', this.activeItem.json.schema.properties);
// Returns {"text000":{"title":"Text (000)","type":"string"}}
I need something to return:
{"title":"Text (000)","type":"string"}
SOLUTION thanks #jaredgorski:
const properties = this.activeItem.json.schema.properties;
const propertiesKeys = Object.keys(properties);
const propertiesKeysFirstVal = Object.keys(properties)[0];
const logProperties = properties[propertiesKeysFirstVal];
console.log('PROPERTIES KEYS:', propertiesKeys);
console.log(
'VALUES OF FIRST PROPERTIES KEY:',
propertiesKeysFirstVal
);
console.log('RESULT:', logProperties);
PROPERTIES KEYS: ["text000"]
wrux-wrux-form-builder.js:1782 VALUES OF FIRST PROPERTIES KEY: text000
wrux-wrux-form-builder.js:1783 RESULT: {title: "Text (000)", type: "string"}
You need to remember that activeItem is an array. As long as you include the index (in this case the first index, which is [0]), you can access the json property (or key) and continue down the chain to retrieve the values in text000.
The other trick here is that you're wanting to access the first key in properties, but you don't know the name of that key yet. So what you need to do is actually make an array of the keys and then find out the name of the first key in that properties object. To do this, you can use Object.keys(), a method which turns the keys of an object into an array. Once you have the name of this key, you only need to use bracket notation on the properties object to find the value for this key. I'll show you how this works in the snippet below.
Here are some references so that you can learn more about how this works:
MDN page on the Object.keys() method
Accessing JavaScript
object properties: Bracket notation vs. Dot notation
And here's the working example:
const activeItem = [
{
"dnd": {
"index": 0,
"active": true,
"group":"common",
"label":"Text (000)",
"type":"text",
"icon":"text_fields",
"fontSet":"material-icons",
"class":""
},
"json": {
"schema": {
"properties": {
"text000":{
"title":"Text (000)",
"type":"string"
}
},
"required":["text000"]
},
"layout":[
{
"key":"text000",
"description":"",
"floatLabel":"auto",
"validationMessages": {
"required":"Required"
}
}
]
}
}
]
// This is the dirty looking version:
const logPropertiesDirty = activeItem[0].json.schema.properties[Object.keys(activeItem[0].json.schema.properties)[0]]
console.log("First, the dirty version where we don't save anything to variables. Everything is laid out here.")
console.log('WHAT WE DID:', 'activeItem[0].json.schema.properties[Object.keys(activeItem[0].json.schema.properties)[0]]')
console.log('RESULT:', logPropertiesDirty)
console.log('=================================================')
// This is the cleaner version, using variables to store things as we go:
const properties = activeItem[0].json.schema.properties;
const propertiesKeys = Object.keys(properties);
const propertiesKeysFirstVal = Object.keys(properties)[0];
const logPropertiesClean = properties[propertiesKeysFirstVal];
console.log('Now, the cleaner version. We save some values to variables to make things more readable.')
console.log('PROPERTIES OBJECT:', properties)
console.log('PROPERTIES KEYS:', propertiesKeys)
console.log('NAME OF FIRST PROPERTIES KEY:', propertiesKeysFirstVal)
console.log('RESULT:', logPropertiesClean)
Regarding what to call these things, I've always thought of Objects as generally consisting of "key-value pairs". Keys can also be called properties and values can also be called contents (I guess).
myObject = {
key1: value1,
property2: contentsOfProperty2
}
At the end of the day, clear communication is all that counts! So, whatever names you come up with (as long as they make reasonable sense), I'm sure people won't be jerks about it unless they feel like they have something to prove.
You should be able to use Object.values over this.activeItem.json.schema.properties:
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.values(object1));
// expected output: Array ["somestring", 42, false]
It is not supported across the map yet, but you should be able to load a polyfill if you need it.
I am currently unsure as to how to edit one of my objects in my javascript (React JS) program. I am implementing web sockets into my program, and so I am receiving an object that I need to use to edit another object in my program.
Here are the two summarized objects (with only updated properties included):
objectWeAreEditingWith = {
path: [
"playerStatuses",
"id1" //really is an id like "b02a507f-31..."
],
value: [
true,
"Random"
]
}
objectWeAreEditing = {
property1: ...
property2: ...
...
playerStatuses: {
id1: [
false,
"Generalist"
]
}
...
moreProperties: ...
}
Some details about the objects. The "objectWeAreEditingWith" will always only have a path and value property. The path property just contains the keys that are required access the correct key in "objectWeAreEditing". The value property just contains the variable values to change in the key that was detailed in the path property. "ObjectWeAreEditing" can contain any number of properties. Another thing to note is that the values in the array "value" is always in the same order (and size) as the property we are targeting in "objectWeAreEditing". "path", "value", and "id1" could techincally be any size (very long path / many variables), but id1 and value will always have the same length / have the values in the same order like I said before.
For this case, I am trying to do:
objectWeAreEditing[playerStatuses][id1][0] = objectWeAreEditingWith[value][0];
AND
objectWeAreEditing[playerStatuses][id1][1] = objectWeAreEditingWith[value][1];
The problem is that, of course, I don't know that I am editing:
objectWeAreEditing[playerStatuses][id1]
because this path is given by "objectWeAreEditingWith".
I also don't know that I am only editing:
objectWeAreEditing[playerStatuses][id1][0];
AND
objectWeAreEditing[playerStatuses][id1][1];
because the amount of variables I am editing is given in "objectWeAreEditingWith".
The solution for the second portion is to go into the "value" property and check its length and iterate through that many variables inside of (id1 in this case). I do not, however, have any clue how to iterate through a path of keys inside of an object.
If you want to set data in object2 depending on object1, one solution is:
let object1 = {
path: [
"playerStatuses",
"id1"
],
value: [
true,
"Random"
]
};
let object2 = {
property1: true,
property2: true,
playerStatuses: {
id1: [
false,
"Generalist"
]
}
};
console.log(object2);
(function setObjectFrom(object1, object2) {
var i = 0;
if (object1.path.length <= 0) {
throw "Cannot set empty path";
}
var currentToKey = object1.path[i];
(function walkerObject(object, value) {
for (let key in object) {
if (key == currentToKey) {
if (object1.path.length-i <= 1) {
object[key] = value;
}
else {
i++;
currentToKey = object1.path[i];
walkerObject(object[key], value); // call itself
}
}
}
})(object2, object1.value);
})(object1, object2);
console.log(object2);
Here:
A function (setObjectFrom) is defined to set an attribute of a object2 depending of object1.path and object1.value. It define another function named walkerObject. This function does the following: each time it find a value of path (let name it vPath) as a key of object1, it verify if it is the last key:
When it is the last key, it set value as value of object2[vPath]
If it is not the last key, the walkerObject call itself again looking for the next value of path, but with object2[vPath] as object2
This function is not bullet proof, that mean, it does not handle error such as object1.path is not found inside object2 and others case.
Corresponding jsBin
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/
I have an object that's nested like the example below.
var posts = {
"post1": {
"slug": "slug1",
"title": "title1",
},
"post2": {
"slug": "slug2",
"title": "title2",
}
};
I'm trying to write a for/in loop that will allow me to iterate through this object.
var testLoop = function () {
for (var prop in posts){
post = prop;
console.log(post); // Outputs post1 and post2
console.log(post.slug); // Outputs undefined
}
}
As seen above, I can't store and later access the properties of each iterated object. Only the name of the object is stored and logged. When I run typeof, I see that it's not even an object, it's just a string.
How can I correctly store each iterated properties as objects (post1, post2 etc.) during the loop so I can access their properties using dot notation?
When you use
for (var prop in posts){ ... }
It loops over the string keys in the posts object.
The main point here is that prop will be a string, and not an object like your current code is expecting.
As users in the comments suggested, because prop is the object key as a string, you need to use posts[prop] to refer to the actual object.
Here is some updated code.
var testLoop = function () {
for (var prop in posts){
post = posts[prop]; // ** this is line that needs to be modified **
console.log(post); // Outputs post object
console.log(post.slug); // this should work now
}
}
I am very new to JS and I was just going through the syntax of modal.js. Basically I have a small difficulty, a lot of classical JS plugins use the below skeleton code for the plugin:
var Modal = function(element , options){
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.isShown = null
this.$backdrop =
this.scrollbarWidth = 0
}
Modal.prototype.toggle = function (_relatedTarget) {
// do something
}
Modal.prototype.show = function (_relatedTarget) {
// do something
}
var data = new Modal(somthing , radnom);
// now if we assume that option is "show",
//the show function in Modal will be executed
// but my question is data is not an array, so how can we use
// [] square brackets to access the properties of Modal/data ??
data[option](_relatedtarget);
Now my question is about accessing the properties of a plugin, see how a function is being called using the following syntax:
data[option](_relatedtarget);
See my comment in the code. How can we access the properties of data using []; it's not an array, right?
[] are not just for arrays
You can use [] to access properties on an object too.
You can use
data["show"] to access the show method
OR
data.show which is the same thing
One advantage of the [] is that you can use a variable within the brackets
var option = "show";
data[option](something); // call the `show` method on `data`
If you know the method you want to call, using the . is much nicer looking in the code
data.show(something); // much quicker (to type), and prettier
JavaScript has arrays:
var anArray = [ 1, 2, 3, 4 ];
and associative arrays (also known as maps):
var anAssociativeArray = { first: "No. 1", second: 2, somethingElse: "Other" };
both of these data structures can be accessed via []:
anArray[3] // will get the element of the array in position 3
// (starting counting frrom 0).
anAssociativeArray['first'] // will get the element of the associative array with the
// key 'first'.
Associative arrays can also be accessed via the .key notation:
anAssociativeArray.first // will also get the property with key 'first'.
The . notation can be used if you know the key you want to access but if you want to dynamically select which key then you need to use the [] notation.
var whichOptionToPick = 'somethingElse';
var value = anAssociativeArray[ whichOptionToPick ]; // will get the value "Other".