I have an array of objects. Each object looks like this:
{
"key": "pQSa6jgmsbFnQgJ1memDJ",
"type": "div",
"props": {
"id": "pQSa6jgmsbFnQgJ1memDJ",
"style": {
"height": "100px",
"backgroundColor": "#de4141"
},
"className": ""
},
"selected": true,
"childNodes": [{
"key": "pQSa6jgmsbFnQgJ1memDJ",
"type": "div",
"props": {
"id": "VrrQ1rMUOF6IOOKAZomor",
"style": {
"height": "100px",
"backgroundColor": "#de4141"
},
"className": ""
},
"selected": false,
"childNodes": []
}]
}
The problem is that each object can have childNodes
, and those childs can have also more childs...
The property that I want to change is selected
. This property defines wether the object is selected or not and therefore display a different className in the DOM. I have a function to deselect all (change all the object's selected property to false) that looks like this, where content
is a React state
, the array containing this objects:
function () {
const $ = _.cloneDeep(content);
const z = $.map((c) => {
let y = c;
if (y?.childNodes && y.childNodes.length > 0) {
y.childNodes = y.childNodes.map((h) => {
let x = h;
x.selected = false;
return x;
});
}
y.selected = false;
return y;
});
setContent(z);
setActive(null);
}
But this will only change the first childNodes. What if these childNodes have also more childNodes? I would need to do a map, again, for those childNodes manually. Is there a way to do this (e.g using lodash
,which I'm alreay using for cloneDeep()
)?
CodePudding user response:
You could use a recursive approach to set the required property values. We'd create a function like 'setPropertyDeep', pass along the property value required.
This will update the object tree to any depth.
const input = { "key": "pQSa6jgmsbFnQgJ1memDJ", "type": "div", "props": { "id": "pQSa6jgmsbFnQgJ1memDJ", "style": { "height": "100px", "backgroundColor": "#de4141" }, "className": "" }, "selected": true, "childNodes": [{ "key": "pQSa6jgmsbFnQgJ1memDJ", "type": "div", "props": { "id": "VrrQ1rMUOF6IOOKAZomor", "style": { "height": "100px", "backgroundColor": "#de4141" }, "className": "" }, "selected": false, "childNodes": [] }] }
function updatePropertyDeep(obj, property, value) {
for(let k in obj) {
if (k === property) {
obj[property] = value;
} else if (obj[k] && typeof(obj[k]) === 'object') {
updatePropertyDeep(obj[k], property, value);
}
}
return obj;
}
console.log('Setting true:', updatePropertyDeep(input, 'selected', true))
console.log('Setting false:', updatePropertyDeep(input, 'selected', false))
.as-console-wrapper { max-height: 100% !important; }
CodePudding user response:
use recursion
function updateChild(child){
if (!child || !Array.isArray(child)) {
return
}
return child.map(el => {
return {
...el,
selected: false,
childNodes: updateChild(el.childNodes)
}
})
}
function main() {
return updateChild(content);
//setContent(z);
//setActive(null);
}
const content = [
{
"key": "pQSa6jgmsbFnQgJ1memDJ",
"type": "div",
"props": {
"id": "pQSa6jgmsbFnQgJ1memDJ",
"style": {
"height": "100px",
"backgroundColor": "#de4141"
},
"className": ""
},
"selected": true,
"childNodes": [{
"key": "pQSa6jgmsbFnQgJ1memDJ",
"type": "div",
"props": {
"id": "VrrQ1rMUOF6IOOKAZomor",
"style": {
"height": "100px",
"backgroundColor": "#de4141"
},
"className": ""
},
"selected": false,
"childNodes": []
}]
}
]
document.getElementById('result').innerHTML = JSON.stringify(main(), null, 2)
<pre id="result"></pre>