Reputation: 390
The following example demonstrates what I would like to achieve:
const data_template = {
key: 1,
data_object: {
data1: 1,
data2: 2,
data3: 3
},
data_array: [
{ key: 1, data1: 1 },
{ key: 2, data1: 2 },
{ key: 3, data1: 3 }
]
}
let data = [];
data.push({ ...data_template, key: 1 });
data.push({ ...data_template, key: 2 });
console.log(data);
By using destructuring I can easily modify my "template object" (data_template
) while adding instances of it to my "data array". The result of the code above is:
[
{
key: 1,
data_object: { data1: 1, data2: 2, data3: 3 },
data_array: [ [Object], [Object], [Object] ]
},
{
key: 2,
data_object: { data1: 1, data2: 2, data3: 3 },
data_array: [ [Object], [Object], [Object] ]
}
]
As you can see, there are 2 objects in my array (data
), each with a unique key (1 and 2, respectively).
Now my question: How can I modify the keys within data_array
, which is an array within my "data template"? Is there a smart way to do this by destructuring as well?
Upvotes: 3
Views: 716
Reputation: 5514
The short answer
No, you cant.
JavaScript destructuring only allows you to override root level keys of an object, which replaces their value.
(You also usually wouldn't do this, to keep cognitive complexity low.)
The long answer
There are actually better ways to do this.
Usually when creating a new object by spreading becomes more complex, you'd simply create a function for each level of nesting, and give it a better name than I did, that correlates to your domain.
This is exactly what functions are made for; to split pieces of code to reduce complexity.
Simple example
function createDataEntry(key, data) {
return { key, data }
}
function createRecord(key, data) {
return {
key,
dataObject: {
data,
},
dataArray: [
createDataEntry(key, data),
// or simply:
// { key, data },
]
}
}
let data = [];
data.push(createRecord(1, 'foo'));
data.push(createRecord(2, 'bar'));
console.log(JSON.stringify(data, null, 2));
produces
[
{
"key": 1,
"dataObject": {
"data": "foo"
},
"dataArray": [
{
"key": 1,
"data": "foo"
}
]
},
{
"key": 2,
"dataObject": {
"data": "bar"
},
"dataArray": [
{
"key": 2,
"data": "bar"
}
]
}
]
Add + Edit example
If you want to add or edit an entry from that data array, you'll have to do a check to see if an entry already exists.
If it already exists, update it using map.
If it does not exist, use array.push().
function addOrUpdateEntry(myObject, key, data) {
let updated = false;
const updatedObject = {
...myObject,
items: myObject.items.map(member => {
if (member.key === key) {
updated = true;
return { ...member, data };
}
return member;
})
};
if (!updated) {
updatedObject.items.push({ key, data });
}
return updatedObject;
}
let data = {
items: []
};
data = addOrUpdateEntry(data, 1, "foo");
data = addOrUpdateEntry(data, 2, "bar");
data = addOrUpdateEntry(data, 2, "baz");
console.log(JSON.stringify(data, null, 2));
Which will output
{
"items": [
{
"key": 1,
"data": "foo"
},
{
"key": 2,
"data": "baz"
}
]
}
Note that mutating an existing object can easily make for undesired behaviour in JavaScript, hence the creation of a new object and returning that from the function.
This concept is called immutability
.
Upvotes: 0
Reputation: 8718
Depends on what you're trying to do.
If you simply want to clone the array with extra elements:
data.push({
...data_template,
key: 1,
data_array: [
...data_template.data_array,
{ key: 4, data1: 4},
],
});
If you want to e.g. add a new field to all the objects inside data_array
:
const data_template = {
key: 1,
data_object: { data1: 1, data2: 2, data3: 3 },
data_array: [ { key: 1, data1: 1 }, { key: 2, data1: 2 }, { key: 3, data1: 3 }]
}
console.log({
...data_template,
key: 1,
data_array: data_template.data_array.map(d => ({ ...d, newField: 123 })),
});
key
field
Otherwise I can't immediately think of any other destructuring "tricks" you could use.
Upvotes: 1