I have this Javascript object:
{
title: "Securities Finance Trade Entry",
children: [
{
containerType: "Tabs",
children: [
{
title: "Common",
children: [
{
containerType: "Row",
children: [
{
input: "ComboBox",
label: "Trade Type",
options: ["Repo", "Buy/Sell", "FeeBased"],
value: "FeeBased"
},
{
input: "ComboBox",
label: "Direction",
options: ["Loan", "Borrow"],
value: "Borrow"
}
]
},
{
containerType: "Row",
children: [
{
containerType: "Column",
children: [
{
containerType: "Row",
children: [
{
input: "Text",
label: "Book",
value: "test"
},
{
input: "Text",
label: "Counterparty",
value: "test"
}
]
},
{
containerType: "Row",
children: [
{
input: "Date",
label: "StartDate",
value: "10/02/2021"
},
{
input: "Date",
label: "EndDate",
value: "10/02/2021"
}
]
},
{
containerType: "Row",
children: [
{
input: "Text",
label: "Security",
value: "test"
},
{
input: "Numeric",
label: "Quantity",
value: "test"
}
]
}
]
}
]
}
]
}
]
}
]
}
given a specific label I need to find the object with that label and then replace the value, the issue I have is that this format could be more nested and I cant look at any specific level, I need to look at all objects at all levels then just replace the value in the one where the label matches. I have tried recursion but can't get it to work, please can anyone advise?
EDIT:
This is my attempt but it fails badly :)
const deepReplace = (obj, id, value) => {
if (obj.children) {
obj = obj.children.map((childObj) => {
if (typeof childObj === "object") {
deepReplace(childObj, id, value)
}
})
return obj;
};
if (obj.label === id) {
obj['value'] = value;
return obj
};
};
const newObj = deepReplace(myObj, 'TradeType', 'Repo')
CodePudding user response:
This problem seems to be a good candidate for recursion. Since we have to do a repeated operation multiple times and we are not sure how many.
- Base case: if label is there and is same as required then change the value
- If label does not exist or is not same then check if the property children exists and then iterate over it and repeat 1 and 2.
// passed (obj, "Book", "changed")
const replaceValueOfTheLabel = (obj, label, value) => {
if (obj.label === label) {
return obj.value = value;
}
if (obj.children)
for (const ob of obj.children) {
replaceValueOfTheLabel(ob, label, value)
}
}
const obj = {
title: "Securities Finance Trade Entry",
children: [{
containerType: "Tabs",
children: [{
title: "Common",
children: [{
containerType: "Row",
children: [{
input: "ComboBox",
label: "Trade Type",
options: ["Repo", "Buy/Sell", "FeeBased"],
value: "FeeBased"
},
{
input: "ComboBox",
label: "Direction",
options: ["Loan", "Borrow"],
value: "Borrow"
}
]
},
{
containerType: "Row",
children: [{
containerType: "Column",
children: [{
containerType: "Row",
children: [{
input: "Text",
label: "Book",
value: "test"
},
{
input: "Text",
label: "Counterparty",
value: "test"
}
]
},
{
containerType: "Row",
children: [{
input: "Date",
label: "StartDate",
value: "10/02/2021"
},
{
input: "Date",
label: "EndDate",
value: "10/02/2021"
}
]
},
{
containerType: "Row",
children: [{
input: "Text",
label: "Security",
value: "test"
},
{
input: "Numeric",
label: "Quantity",
value: "test"
}
]
}
]
}]
}
]
}]
}]
}
replaceValueOfTheLabel(obj, "Book", "changed");
console.log(obj);
CodePudding user response:
If you're interested in an answer that doesn't mutate your original data but returns a copy with the appropriate values replaced, it might look like this:
const deepReplace = (label, value) => (obj) => Object (obj) == obj
? { ... obj,
... (obj .label == label ? {value} : {}),
... (obj .children ? {children: obj .children .map (deepReplace (label, value))} : {})
}
: obj
const input = {title: "Securities Finance Trade Entry", children: [{containerType: "Tabs", children: [{title: "Common", children: [{containerType: "Row", children: [{input: "ComboBox", label: "Trade Type", options: ["Repo", "Buy/Sell", "FeeBased"], value: "FeeBased"}, {input: "ComboBox", label: "Direction", options: ["Loan", "Borrow"], value: "Borrow"}]}, {containerType: "Row", children: [{containerType: "Column", children: [{containerType: "Row", children: [{input: "Text", label: "Book", value: "test"}, {input: "Text", label: "Counterparty", value: "test"}]}, {containerType: "Row", children: [{input: "Date", label: "StartDate", value: "10/02/2021"}, {input: "Date", label: "EndDate", value: "10/02/2021"}]}, {containerType: "Row", children: [{input: "Text", label: "Security", value: "test"}, {input: "Numeric", label: "Quantity", value: "test"}]}]}]}]}]}]}
console .log (deepReplace ('Counterparty', '*** New value ***') (input))
.as-console-wrapper {max-height: 100% !important; top: 0}
We test if our input is an object. If not, we simply return it. If it is, we create a new object by including all the root properties of the object, replacing a value
property if we have the right label
, and then recurring on the children
nodes.
There are all sorts of benefits to immutable data. I would recommend adopting it when you can.