This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 7 years ago.
I have a javascript object, something like this :
var obj = { simpleName: "some name" name: { firstName: "anudeep", lastName : "rentala" }, address: { country: "XZ", state:"DF" } }
I also have another object like this :
var foo = { loc = "name.firstName" }
Depending on the foo.loc value, I'd have to access the value in obj object.
In this scenario, I'd need to access obj.name.firstname.
So, far, I've tried something like this:
var props = foo.loc.split(".");
for(var prop in props)
{
if (obj.hasOwnProperty(prop))
{
alert(obj[prop])
}
}
My problem is, I can now access only the name property of obj object, how do I step into it, like name.firstName, I'm aware that obj[name][firstName] would work, but how do i do this dynamically ? Like extend this to obj["prop1"]["prop2"]["prop3"] . .. .["propn"]
There are few missing ,, and firstname vs firstName, but if you fix those, then this works great:
var obj = { simpleName: "some name", name: { firstName: "anudeep", lastName : "rentala" }, address: { country: "XZ", state:"DF" } }
var foo = { loc: "name.firstName" }
var props = foo.loc.split(".");
var output = props.reduce( function(prev,prop) {
if (prev.hasOwnProperty(prop)) {
return prev[prop]
} else {
// however you want to handle the error ...
}
}, obj);
alert(output);
You could fix your code like this:
var props = foo.loc.split(".");
var current = obj;
for(var prop in props)
{
if (current.hasOwnProperty(prop))
{
current = current[prop];
alert(current )
}
}
but that probably won't be very useful once you start having more complex "selectors", for example, using arrays ("names[2].firstname").
Here is a function:
var obj = { simpleName: "some name", name: { firstName: "anudeep", lastName : "rentala" }, address: { country: "XZ", state:"DF" } };
var foo = { loc: "name.firstName" };
var checkObj = function(obj, props) {
var temp = obj;
for(var i = 0, len = props.length; i < len; i++) {
if(temp.hasOwnProperty(props[i])) {
temp = temp[props[i]];
}
else return false;
}
return temp;
};
console.log(checkObj(obj, foo.loc.split('.')));
Related
var student={
student1:{
name:"John",
}
}
var student2={
name:"Doe"
}
Resultamt object should contain both student object with their object's name
Like this :-
students={
student1={name:"John"},
student2={name:"Doe"}
}
You can use object spread to solve this.
e.g
let student = {
student1: {
name: "John",
},
};
let student2 = {
name: "Doe",
};
let students = {
...student,
student2,
};
console.log(students);
Using spread operation you can combine them.
const students = {
...student1,
...student2
};
In Firestore you can update fields in nested objects by a dot notation (https://firebase.google.com/docs/firestore/manage-data/add-data?authuser=0#update_fields_in_nested_objects). I wonder how to make that work in Typescript / Javascript.
For example the following object:
const user = {
id: 1
details: {
name: 'Max',
street: 'Examplestreet 38',
email: {
address: 'max#example.com',
verified: true
}
},
token: {
custom: 'safghhattgaggsa',
public: 'fsavvsadgga'
}
}
How can I update this object with the following changes:
details.email.verified = false;
token.custom = 'kka';
I already found that Lodash has a set function:
_.set(user, 'details.email.verified', false);
Disadvantage: I have to do this for every change. Is their already a method to update the object with an object (like firestore did)?
const newUser = ANYFUNCTION(user, {
'details.email.verified': false,
'token.custom' = 'kka'
});
// OUTPUT for newUser would be
{
id: 1
details: {
name: 'Max',
street: 'Examplestreet 38',
email: {
address: 'max#example.com',
verified: false
}
},
token: {
custom: 'kka',
public: 'fsavvsadgga'
}
}
Does anyone know an good solution for this? I already found more solutions if I only want to change one field (Dynamically set property of nested object), but no solution for more than one field with one method
I think you are stuck with using a function but you could write it yourself. No need for a lib:
function set(obj, path, value) {
let parts = path.split(".");
let last = parts.pop();
let lastObj = parts.reduce((acc, cur) => acc[cur], obj);
lastObj[last] = value;
}
set(user, 'details.email.verified', false);
if what you want to do is merge 2 objects then it is a bit trickier:
function forEach(target, fn) {
const keys = Object.keys(target);
let i = -1;
while (++i < keys.length) {
fn(target[keys[i]], keys[i]);
}
}
function setValues(obj, src) {
forEach(src, (value, key) => {
if (value !== null && typeof (value) === "object") {
setValues(obj[key], value);
} else {
obj[key] = value;
}
});
}
let obj1 = {foo: {bar: 1, boo: {zot: null}}};
let obj2 = {foo: {baz: 3, boo: {zot: 5}}};
setValues(obj1, obj2);
console.log(JSON.stringify(obj1));
One solution in combination with lodash _.set method could be:
function setObject(obj, paths) {
for (const p of Object.keys(paths)) {
obj = _.set(obj, p, paths[p]);
}
return obj;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have an object and I want one of the values to be the name of the parent key:
{
name: 'Jon',
address: {
city: 'Vienna',
parent: <How can I dynamically set this to 'address'>
}
}
well i cant understand from your question if you handle nested objects with more then 1 level but this code will work for the first level. if you want unlimited levels you need to do it with recursion
const obj = {
name: 'Jon',
address: {
city: 'Vienna'
}
}
for(let i in obj){
if(typeof obj[i] === 'object'){
obj[i].parent = i;
}
}
console.log(obj)
We can achieve this by making a recursive function which recursively updates all the levels inside the object and child objects with the parent property.
Here is a recursive function which will work for n-levels.
var obj = {
name: 'Jon',
address: {
city: 'Vienna',
pincode :{
val : 110,
Area : {
val : "xyz"
}
},
},
designation : {
post : "Manager",
salary : {
value : "100"
}
}
}
function updateParent(obj,parent){
if(parent)
obj.parent = parent;
for(var key in obj){
if(obj[key].constructor.toString().indexOf("Object") >= 0){
updateParent(obj[key],key);
}
}
}
updateParent(obj);
console.log(obj);
The approach I took was to make the object iterable then use a for...of to search for the desired child property and change the value to it's parent object's name:
var data = {
name: 'Jon',
address: {
city: 'Vienna',
parent: '<How can I dynamically set this to \'address\'>'
}
};
data[Symbol.iterator] = function() {
var i = 0;
var keys = Object.keys(this);
return {
next: function() {
var value = keys[i],
done = false;
i++;
if (i > keys.length) {
done = true;
}
return {
value,
done
}
}
}
}
function setChildProperty(parentPropertyName, childPropertyName) {
for (prop of data) {
if (prop == parentPropertyName) {
data[prop][childPropertyName] = prop;
}
}
}
//Before
console.log(data);
setChildProperty("address", "parent")
//After
console.log(data);
I've got a flat JavaScript object like this:
{
id: 3726492,
kind: 'user',
permalink: 'nicholas',
username: 'Nicholas',
...
a lot more attributes
}
I'd like to create a new object which only has a subset of the attributes of the original object.
Something like
var newObject = oldObject.fields(['id', 'username']);
newObject would be
{
id: 3726492,
username: 'Nicholas'
}
Is there already something like this?
Try this
function pick(data, keys) {
var result = {};
keys.forEach(function (key) {
if (data.hasOwnProperty(key)) {
result[key] = data[key];
}
});
return result;
}
var data = {
id: 3726492,
kind: 'user',
permalink: 'nicholas',
username: 'Nicholas'
}
var newData = pick(data, ['id', 'kind']);
console.log(newData);
In underscorejs or lodash there is method .pick
var data = {
id: 3726492,
kind: 'user',
permalink: 'nicholas',
username: 'Nicholas',
};
var newObject = _.pick(data, 'id', 'username');
console.log(newObject);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
You can use Array.prototype.reduce to reduce one object to another using the list of properties:
function subset(obj, propList) {
return propList.reduce(function(newObj, prop) {
obj.hasOwnProperty(prop) && (newObj[prop] = obj[prop]);
return newObj;
}, {});
}
var obj = {
id: 3726492,
kind: 'user',
permalink: 'nicholas',
username: 'Nicholas'
};
var newObj = subset(obj, ['id', 'username']);
console.log(newObj);
document.getElementById('json').innerText = JSON.stringify(newObj);
<pre id="json"></pre>
Not built-in, but you can sure define a simple function that does the job:
var original = {a:1112, b:434, c:666, d:222};
function fieldSubset(obj, fields) {
var subsetClone = {};
for( var i=0,l=fields.length; i<l; i++) {
// This can prevent filling undefined as properties
if(obj.hasOwnProperty(fields[i])) {
subsetClone[fields[i]] = obj[fields[i]];
}
}
return subsetClone;
}
fieldSubset(original, ["a", "c"]);
You can also use this in Object.prototype, but be aware that this might happen to conflict with native API in the future versions of JavaScript:
var original = {a:1112, b:434, c:666, d:222};
Object.defineProperty(Object.prototype, "fieldSubset", {
value: function(fields) {
var subsetClone = {};
for( var i=0,l=fields.length; i<l; i++) {
// This can prevent filling undefined as properties
if(this.hasOwnProperty(fields[i])) {
subsetClone[fields[i]] = this[fields[i]];
}
}
return subsetClone;
},
enumerable: false,
configurable: true}
);
original.fieldSubset(["a", "c"]);
One liner using Array.prototype.reduce. We are also using Object.assign. The idea is to keep extending a blank object with the keys found in the filters array. If you see, the reduce function takes a callback function with arg1,arg2,arg3 params as the first argument and an empty object as the second argument. This object will be cloned and extended with the help of the keys specified in the filters array.
var a = {
id: 3726492,
kind: 'user',
permalink: 'nicholas',
username: 'Nicholas',
};
var filters = ["id","username","permalink"];
var sub = Object.keys(a).reduce((arg1,arg2,arg3)=>{ var res = {}; if(filters.indexOf(arg2)>=0){ res[arg2] = a[arg2]; } return Object.assign(arg1,res);},{})
console.log(sub);
You haven't specifically mentioned what is the type of values behind your object's keys. Your current answers cover the shallow copy and deep copy.
Another alternative would be to create a view of the original object. This would be helpful if you have very large data objects and you do not want them copy in the memory.
function View(obj, properties) {
var view = {};
properties.forEach(function(prop) {
Object.defineProperty(view, prop, {
get: function() {
return obj[prop];
},
set: function(val) {
obj[prop] = val;
},
enumerable: true,
configurable: true
});
});
return view;
}
then with your data you can do:
var data = {
id: 3726492,
kind: 'user',
permalink: 'nicholas',
username: 'Nicholas',
},
view = new View(data, ['id', 'username']);
view.id; // 3736492
view.username; // Nicholas
of course you have to be aware that you can change your original object just by view.id = 'something else'. However it is easily preventable.
var config = {
xxx : 'foo'
}
var env = {
foo : {
},
bar : {
}
}
How can I use an objects value to retrieve values from another object?
like:
env.config.xxx?
var object1 = { value : 'hello' }
var object2 = { o : object1 }
alert(object2.o.value);