This question already has answers here:
Dynamically updating a JavaScript object from a string path [duplicate]
(3 answers)
Closed 7 years ago.
I am trying to create a JavaScript object and define its childs on the fly. Therefore, the sub items are dynamic and they may change in run-time.
What I have? var _obj = {};
In the next step, I would like to set some variables in runtime using a function. I can not find an efficient work around to implement the following function:
setObjValue("spaceA.spaceB.id", 1); that save 1 in the following path:
_obj.spaceA.spaceB.id = 1;
I have tried to split the key based on ., and then create the path step by step using a loop. However, since we do not have reference in JavaScript, it is not possible to achieve this.
In other words, how to make a function to add an object in the following pattern?
_obj["spaceA"]["spaceB"]....["id"] = 1;
The number of root steps is not defined before run. So I can not manually use codes. I need to achieve this dynamically like the example function above.
Try this:
function setObjValue(object, path, value) {
var pathArray = path.split('.');
for(var i = 0; i < pathArray.length; i++) {
var name = pathArray[i];
if(i == pathArray.length-1) {
object[name] = value;
} else {
if(!(name in object)) object[name] = {};
object = object[name];
}
}
return;
}
var obj = {};
setObjValue(obj, "test1.test2.sub", "123");
console.log(obj);
Recursion!
var startingObj = {};
var path = "one.two.three.four".split('.');
var val = 7;
function recursiveFun(o, p, v){
var key = p.shift(); // get the current key
if (p.length == 0){
// set key to val and exit
o[key] = val;
return;
}
o[key] = {}; // should check if this exists before overwriting
recursiveFun(o[key], p, v);
}
recursiveFun(startingObj, path, val);
http://plnkr.co/edit/TgoRS0xkXGG6J3DzFxzi?p=info
This one should do it in the most effective way
function setObjValue(path, value) {
path = path.split('.')
var obj = path[0]
// make obj the root
path.shift()
// remove root object from path
while(path.length){
// move further in tree
obj = obj[path[0]]
obj.shift()
}
// assign value
obj = value
}
Related
This question already has answers here:
How can I merge properties of two JavaScript objects dynamically?
(69 answers)
Closed 8 months ago.
i have to create 2 identical object, one with value 'home' and other with value 'mailing' if the condition is true I send them both otherwise I send only 'home', what can I do?
it's correct to do that?
var arrayObj = []
var reqBodyAddress = {};
reqBodyAddress.startDate = new GlideDateTime(current.u_data_inizio_contratto).getNumericValue();
reqBodyAddress.addressType = function(){
var objAddressType1 = {
home:'home'
}
var objAddressType2 = {
mailing:'mailing'
}
if(current.u_domicilio == true){
reqBodyAddress.addressType = objAddressType1 + objAddressType2;
}else{
reqBodyAddress.addressType = objAddressType1;
}
};
arrayObj.push(reqBodyAddress);
var sReqBodyData = JSON.stringify(arrayObj);
Use Object.assign(target, ...sources) [read more] which copies multiple source objects into a target object, and then use a condition on the second object. similar to this:
let a = {foo:'foo'}
let b = {bar:'bar'}
let c = Object.assign(a, (false? b : null));
console.log(c) // {foo:"foo"}
let d = Object.assign(a, (true? b : null));
console.log(d) // {foo:"foo", bar:"bar"}
Test it here
For your case, it would look like this:
reqBodyAddress.addressType = function(){
var objAddressType1 = {
home:'home'
}
var objAddressType2 = {
mailing:'mailing'
}
reqBodyAddress.addressType = Object.assign(
objAddressType1, // target
(current.u_domicilio? objAddressType2 : null) // source
)
}
Note that this doesn't return a copy and will edit the target object. If you don't want to edit any objects when using this function, you can make your target an empty object {} and put all your objects as sources like this:
reqBodyAddress.addressType = function(){
var objAddressType1 = {
home:'home'
}
var objAddressType2 = {
mailing:'mailing'
}
reqBodyAddress.addressType = Object.assign(
{}, // empty target
objAddressType1, // source 1
(current.u_domicilio? objAddressType2 : null) // source 2
)
}
use this
reqBodyAddress.addressType = {
home:'home'
...(current.u_domicilio && {mailing:'mailing'})
}
it's more readable first, and work correct. try to use const and let and avoid to use var for declaring variable in your js code.
your addressType property must get an object for value, right? so why do you use function for its value?
also you can't merge two object with + operator.
i hope this code solve your problem.
Ok, can't get this. I'm trying to push an object property key:value' to an empty object, store it in a variable, then next call retrieve that updated object, and add a new key:value pair to it, then finally grab 2 different random values from the created object. Here's what I've tried:
var obj {};
var storedObject;
var randomResponse1 = pickRand1(obj);
var randomResponse2 = pickRand1(obj);
//first visit to server
if (event.reply == "true") {
obj.1 = 'one';
obj = storedObject;
}
//second visit to server
if (event.reply == "true") {
obj.2 = 'two';
obj = storedObject;
}
//third visit to server
if (event.reply == "true") {
obj.3 = 'three';
obj = storedObject;
}
//fourth visit to server
if (event.reply == "true") {
obj.4 = 'four';
obj = storedObject;
}
//final visit to server
if (event.reply == "true") {
alert(randomResponse1); //it only seems to grab last value
alert(randomResponse2); //also, does this have a chance of
//being the same random result?
}
function pickRand1(obj) {
var result;
var count = 0;
for (var prop in obj)
if (Math.random() < 1/++count)
result = obj[prop];
return result;
}
It's hard to say for sure what the issue is without being able to test the code, but I found a few things that might be causing your problem.
First, dot-notation with Javascript object only works with valid identifiers, which cannot begin with a digit. I switched your code to use bracket-notation, which does work with all valid strings, e.g. obj["1"].
I also edited your random function. In your original function, it seems like you have a 1/1 chance to choose the first key, 1/2 to choose the second, and so on. The new function works by converting obj's to an array, and then choosing a random index for the array, which in turn will give us a random key. Also, as Derek kindly mentioned, you were missing the brackets on your original for-loop :)
Finally, to answer your question in the comments: yes, it's possible that both calls to the random function will return the same object (but that can be easily changed).
I attached a code snippet with my edits below. Let me know if this helps!
Note: I'm not sure what frameworks/libraries/etc you're using with this code, but given the way right now, all of your if-statements will run on the first visit to the server. I think you need to implement some sort of queuing-system to ensure that the if-statements will run on separate visits.
let obj {};
let storedObject;
let randomResponse1 = pickRand1(obj);
let randomResponse2 = pickRand1(obj);
//first visit to server
if (event.reply == "true") {
obj["1"] = 'one';
obj = storedObject;
}
//second visit to server
if (event.reply == "true") {
obj["2"] = 'two';
obj = storedObject;
}
//third visit to server
if (event.reply == "true") {
obj["3"] = 'three';
obj = storedObject;
}
//fourth visit to server
if (event.reply == "true") {
obj["4"] = 'four';
obj = storedObject;
}
//final visit to server
if (event.reply == "true") {
alert(randomResponse1); //it only seems to grab last value
alert(randomResponse2); //also, does this have a chance of
//being the same random result?
}
function pickRand1(obj) {
let keys = Object.keys(obj);
let numKeys = keys.length;
let randomIndex = Math.floor(Math.random() * numKeys);
let randomKey = keys[randomIndex];
let result = obj[randomKey];
return result;
}
it wasn't super clear what you are trying to achieve here but bear in mind;
don't test if( val == "true" ) instead, if your value evaluates to a boolean, just test if( val )
your obj variable is in the global scope, you don't have to keep saving it, you can just add properties to it
if you want your two random properties to be different from each other, remove the first before selecting the second.
var event = {
reply: true
};
var obj = {};
//first visit to server
if (event.reply) {
obj.a = 'one';
}
//second visit to server
if (event.reply) {
obj.b = 'two';
}
//third visit to server
if (event.reply) {
obj.c = 'three';
}
//fourth visit to server
if (event.reply) {
obj.d = 'four';
}
//fifth visit to server
if (event.reply) {
var arr = Object.keys(obj);
var i = Math.floor(Math.random() * arr.length);
var key = arr[i];
console.log(obj[key])
delete obj[key];
arr = Object.keys(obj);
i = Math.floor(Math.random() * arr.length);
key = arr[i];
console.log(obj[key]);
}
What you are doing is setting a property like obj.1 = 'one' (Not to mention that it's not a valid syntax), then assigning storedObject to obj which will make it exactly the same as storedObject discarding any previous changes to obj.
What you need instead is something like this:
obj[1] = 'one'
obj = Object.assign(obj, storedObject)
This will merge the obj content with storedObject content and save the result to obj.
PS: The declaration needs to be like this var obj = {}. Make sure you fix all syntax mistakes before you look for functional issues.
Essentially my I am trying to initialize a JavaScript object and have it contain empty objects with a single key. For example:
getOject('one.two.three')
Would result in the object:
{one:{two:{three:''}}}
As far as I can tell, you can't initialize with dynamic key names unless you use array notation
root[dynamicKey] = 'some variable';
so I need to loop through and based on the number of args initialize each one then assign it's value but the syntax doesn't seem to let me do this in any way that I know of.
So, if it were not a loop it would be like this:
jsonifiedForm[rootKey] = {};
jsonifiedForm[rootKey][childKeys[0]] = {};
jsonifiedForm[rootKey][childKeys[0]][childKeys[1]] = $input.val();
I can't think of a way to do this, I am not typically a JS guy so it might be something simple but I couldn't find anything on Google or Stack Overflow
Thank you in advance!
This function should be what you're looking for.
function getOject(str) {
// this turns the string into an array = 'one.two.three' becomes ['one', 'two', 'three']
var arr = str.split('.');
// this will be our final object
var obj = {};
// this is the current level of the object - in the first iteration we will add the "one" object here
var curobj = obj;
var i = 0;
// we loop until the next-to-last element because we want the last element ("three") to contain an empty string instead of an empty object
while (i < (arr.length-1)) {
// add a new level to the object and set the curobj to the new level
curobj[arr[i]] = {};
curobj = curobj[arr[i++]];
}
// finally, we append the empty string to the final object
curobj[arr[i]] = '';
return obj;
}
Because JavaScript references values in variables instead of copying them "into" variables, we can make our initial value, then make a reference to it which we'll move around as we delve down in:
var getOject = function (k, s) {
// initialize our value for return
var o = {},
// get a reference to that object
r = o,
i;
// we'll allow for a string or an array to be passed as keys,
//and an optional sepeartor which we'll default to `.` if not given
if (typeof k === 'string') {
k = k.split(s || '.');
}
// do we have an array now?
if (k && k.length) {
//iterate it
for (i = 0; i < k.length; i += 1) {
// set a property on the referenced object
r[k[i]] = {};
// point the reference to the new level
r = r[k[i]];
}
}
// send back the object
return o;
}
console.log(getOject('one.two.three'));
console.log(getOject('four|five|six', '|'));
r points to the same thing that o does, initially, and as we move the reference (r) deeper into o and write to it, we're building out o as we go.
The two console.log() calls at the end output the following:
Also notice I let you pass in an array to start with if you feel like it, and made the separator a parameter so that you're not stuck with .
I am doing a project which requires to pass Perl objects to javascript via JSON. I am facing a problem in terms of "intermediate" object definition.
In Perl, object is represented by hash, and programmers don't have to define anything "in the middle". Once a property is created, all intermediate objects are automatically created as hash references. e.g.
$graph{chart}{yAxis}{title} = "Temperature Tracking";
However, once this object is passed to Javascript, if I want to add any new properties in the "intermediate" object, like:
graph.chart.xAxis.title = "Time Sequence";
I'll have an "undefined graph.chart.xAxis" error. Unlike Perl, Javascript doesn't automatically create objects if we simply assign a property for it.
At the moment I have to use below solution:
if (!graph.chart.xAxis) {
graph.chart.xAxis = {};
graph.chart.xAxis.title = "Time Sequence";
}
Unfortunately, in our project the objects passed from Perl are pretty dynamic and there are plenty of other objects that Javascript may not know. Above way makes JS code pretty lengthy and "ugly looking". Are there any better solutions to make Javascript behave like Perl, which means I don't have to create intermediate objects manually?
I'm not sure whether this meets your requirements but a simple function to create the missing objects could look like this:
function insertNode(obj, node, value) {
var segments = node.split('.');
var key = segments.pop();
var ref = obj;
while (segments.length > 0) {
var segment = segments.shift();
if (typeof ref[segment] != 'object') {
ref[segment] = {};
}
ref = ref[segment];
}
ref[key] = value;
};
var x = {};
insertNode(x, 'foo.bar.baz', 'hello world');
alert(x.foo.bar.baz); // "hello world"
Demo: http://jsfiddle.net/sNywt/1/
You may be interested in a library called steeltoe
steelToe(graph).set('chart.xAxis.title', 'Time Sequence');
not sure, if its suitable in your case, but you could check for property existence and create it if does not exist, like:
function use_or_create(obj, prop) {
return (obj.hasOwnProperty(prop)) ? true : (obj[prop] = {});
}
var graph.chart = {}; //your object
//function call to check if property exist before trying to use it
use_or_create(graph.chart, 'xAxis'); //check if xAxis exists and creates one if doesnot
graph.char.xAxis.title = "tested";
Maybe this Object extension will do:
Object.prototype.val = function(prop,val){
prop = /\./i.test(prop) ? prop.split('.') : prop;
if (prop.constructor === Array){
var objnow = this, pr;
while (pr = prop.shift()){
if (!objnow[pr]){
objnow[pr] = {};
}
if (!prop.length) {
objnow[pr] = val;
}
objnow = objnow[pr];
}
for (var l in objnow){
this[l] = objnow[l];
}
} else {
this[prop] = val;
}
}
// usage
var myO = {};
myO.val('a.b.c',3); //=> myO.a.b.c = 3
myO.val('someprop',3); //=> myO.someprop = 3
myO.val('a.b.someprop',5); //=> myO.a.b.someprop = 3
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
javascript - dynamic variables
Dynamic Javascript variable names
I need to create a number of objects on a page and want to name them sequentially. Is there a way to do this in JavaScript?
for (i=0;i<num;i++){
var obj+i = new myObject("param1","param2");
obj+i.someProperty = value;
}
This way I can dynamically create a varying number of objects (dependent on the value "num") and then set their properties appropriately.
I can do this in PHP, is there a way to do it in JavaScript?
This isn't recommended, but does what you're trying to do (if you're running in a browser and not some other js environment).
for (i = 0; i < num; i++) {
window['obj' + i] = new myObject("param1","param2");
window['obj' + i].someProperty = value;
}
obj0.someProperty;
This works because global variables are actually properties of the window object (if you're running in the browser). You can access properties of an object using either dot notation (myObject.prop) or bracket notation (myObject['prop']). By assigning window['obj' + i], you're creating a global variable named 'obj' + i.
The better option is to use an array or parent object to store your objects.
myObjs = {};
for (i = 0; i < num; i++) {
myObjs['obj' + i] = new myObject("param1","param2");
myObjs['obj' + i].someProperty = value;
}
myObjs.obj0.someProperty;
Or use an array like lots of other answers suggest.
That's what arrays are for, to hold a collection of something:
var objs = [];
for (i=0;i<num;i++){
objs[i] = new myObject("param1","param2");
objs[i].someProperty = value;
}
Dynamic variables are almost always a bad idea.
You can create, and you can set/modify properties of that object.
Modified code:
var obj = {}; //
for (i=0;i<num;i++){
obj[i] = new myObject("param1","param2");
obj[i].someProperty = value;
}
I recommend you to use array. as
var obj = []; //
for (i=0;i<num;i++){
obj[i] = new myObject("param1","param2");
obj[i].someProperty = value;
}