Reputation: 73928
I need to create a function that search a property in an object and returns its value. Object could have an arbitrary structure with property nested in other objects.
How could I change my script?
var item = {
id: 10,
properties: {
parent_id: 20,
x: {
y: 100
}
}
}
function getValue(what) {
console.log(item[what]);
}
getValue('id');
// ok return 10
getValue('properties.parent_id')
// undefined - ISSUE here I would like to have returned 20
Upvotes: 2
Views: 251
Reputation: 9066
for a deeply nested object you can use a recursive function to retrieve all the object which are nested inside parent Object.It can be applied to an object literal having three to more number of nested object
var parentObj = {
parentProp: 10,
childObj: {
childProp: 20,
grandChildObj: {
y: {
z:'lol',
places:['newyork','canada','dhaka']
}
}
}
}
var arr=[];
var container=[];
container.push(parentObj);
var count=0;
function getObjNum(obj){ //<= recursive function to retrieve all the nested objects inside parent object
var prop=Object.getOwnPropertyNames(obj);
for(i=0;i<prop.length;i++){
if(typeof(obj[prop[i]])=='object'){
if(!Array.isArray(obj[prop[i]])){
container.push(obj[prop[i]]);
count++;
getObjNum(obj[prop[i]]); // recursive call to getObjNum
}
}
}
}
getObjNum(parentObj); // sent the parent object to getObjNum
function getVal(str){
var split=str.split('.');
container.forEach(function(obj){
if(obj.hasOwnProperty(split[split.length-1])){
console.log(obj[split[split.length-1]]);
}
});
}
getVal('parentObj.parentProp');
getVal('y.z');
Upvotes: 0
Reputation: 114529
You need to create a "path", i.e. a sequence, of keys too access in order. One way is to choose an uncommong separator that is never going to be used for object keys, e.g. |
:
element = obj;
path.split("|").forEach(function(key){
element = element[key];
});
if you cannot exclude any char from the keys then supporting escaping is mandatory; for example you could use ,
to separate keys but allowing @,
to mean a comma is part of the key and @@
meaning an at-sign is part of the key.
element = obj;
(path+",").match(/([^@,]|@.)*,/g).forEach(function(x){
element = element[x.slice(0,-1).replace(/@(.)/g, "$1")];
});
for example the path "1,2,x,y@,z,,w@@"
can be used to access
obj[1][2].x["y,z"][""]["w@"]
Upvotes: 2
Reputation: 3343
The code below makes flat obj so to access like that.
var flatten = function(obj,into,prefix){
into = into ||{};
prefix = prefix || '';
_.each(obj,function(val,key){
if(obj.hasOwnProperty(key)){
if(val && typeof val === 'object'){
flatten(val,into,prefix + key + '.');
}else{
into[prefix + key] = val;
}
}
});
return into;
};
The working JSFiddle is here http://jsfiddle.net/fper2d73/
The complete code is
var item = {
id: 10,
properties: {
parent_id: 20,
x: {
y: 100
}
}
}
var flatten = function(obj,into,prefix){
into = into ||{};
prefix = prefix || '';
_.each(obj,function(val,key){
if(obj.hasOwnProperty(key)){
if(val && typeof val === 'object'){
flatten(val,into,prefix + key + '.');
}else{
into[prefix + key] = val;
}
}
});
return into;
};
var _item = flatten(item);
function getValue(what) {
console.log(_item[what]);
}
getValue('id');
// returns 10
getValue('properties.parent_id')
// returns 20
getValue('properties.x.y')
//returns 100
Upvotes: 0
Reputation: 1157
You can provide a syntax to access these properties in the getValue function parameter. For example, to access properties.parent_id you can use 'properties.parent_id'.
Then the getValue function should be written as the following:
function getValue(prop) {
if (typeof(prop) !== 'string')
throw 'invalid input string';
props = prop.split('.');
var value = item[props[0]];
for(var i = 1, l = props.length; i < l; i++) {
value = value[props[i]];
}
return value;
}
Example:
getValue('properties.parent_id'); //returns 20
Upvotes: 3