Given a strings like 'param1.param2.param3' and a value that should be set on the last parameter, is there a better way than the following to dynamically create an Object and reuse the function to create more parameters on the Object, some which may share a parent parameter? This function also assumes every parameter on the parent Object is an Object with parameters. The purpose is to construct a JSON Object dynamically for a PUT/PATCH request.
function(o,prop,val) {
prop = prop.split('.');
prop.forEach(function(property,i){
if(i===0 && typeof(o[property]) === 'undefined'){
o[property] = {};
if(prop.length === 2){
o[prop[0]][prop[1]] = val;
}
}
else if(i===1 && typeof(o[prop[0]][property]) === 'undefined'){
o[prop[0]][property] = {};
if(prop.length === 3){
o[prop[0]][prop[1]][prop[2]] = val;
}
} else if(i===1 && typeof(o[prop[0]][property]) === 'object'){
if(prop.length === 3){
o[prop[0]][prop[1]][prop[2]] = val;
}
}
else if(i===2 && typeof(o[prop[0]][prop[1]][property]) === 'undefined'){
o[prop[0]][prop[1]][property] = {};
if(prop.length === 4){
o[prop[0]][prop[1]][prop[2]][prop[3]] = val;
}
} else if(i===2 && typeof(o[prop[0]][prop[1]][property]) === 'object'){
if(prop.length === 4){
o[prop[0]][prop[1]][prop[2]][prop[3]] = val;
}
}
});
return o;
};
Here is a Fiddle https://jsfiddle.net/cn25o1vf/
1 Answer 1
It seems odd to special-case the string "object"
when preparing an object for serialization, so I came up with the following code:
var createObjectFromParam = function (o, prop, val) {
var parts = prop.split('.');
var last = o;
while (parts.length) {
var part = parts.shift();
if (parts.length > 0) {
last[part] = last[part] || {};
last = last[part];
} else {
last[part] = val; // Add conditional expressions here
}
}
return last;
}
The code does the following:
- Creates a temporary variable (
last
) to contain the current "level" of the object hierarchy. - Loops through the array. Note that
while (parts.length)
will stop the loop when there are no longer parts in the array. - Take the next part of the
prop
.shift
pulls the first element of the array out. - If we're not at the last element
- If the element with the specified name exists at the level, use that
- If not, create an object at that level
- Otherwise, add a property with the specified value to the object.
- Finally, return the created object.
Given the example in the jsFiddle (updated here), this would produce the following structure:
{
"ready": {
"set": "go"
},
"another": "object",
"happy": {
"happy": {
"joy": "joy",
"foo": "bar",
"happy": "happy"
}
}
}
To keep that original special-casing, just replace the commented line with something like:
last[part] = val === 'object' ? {} : val === 'undefined' ? : undefined : val;
'{ "another": {} }'
), whereas I would have expected it to create a property with the string"object"
, iow:'{ "another": "object" }'
. \$\endgroup\$