Change object property in nested array
I have an array:
const array = [ { id: 1, parent_id: 0, visible: true }, { id: 2, parent_id: 0, visible: true }, { id: 3, parent_id: 1, visible: true }, { id: 4, parent_id: 3, visible: true }, { id: 5, parent_id: 4, visible: true }, { id: 6, parent_id: 4, visible: true }, { id: 7, parent_id: 3, visible: true }, { id: 8, parent_id: 2, visible: true } ]
I want to create a function with arguments ID and ARRAY, that return new array with VISIBLE = FALSE for this ID and every nested child by PARENT_ID.
My effort is like this
const result = [] const findFitstHandler = (id, arr) => { let j for (let i in arr) { if (arr[i].id === id) { result.push(arr[i].id) j = arr[i].id } } findNested(j, arr) return array.map(item => { if (result.includes(item.id)) { return { ...item, visible: false } } else { return item } }) } const findNested = (id, arr) => { for (let i in arr) { if (arr[i].parent_id === id) { result.push(arr[i].id) findNested(arr[i].id, arr) } } }
I’m sure there is a more elegant solution. Please, help me
Try with array map method:
const array = [ { id: 1, parent_id: 0, visible: true }, { id: 2, parent_id: 0, visible: true }, { id: 3, parent_id: 1, visible: true }, { id: 4, parent_id: 3, visible: true }, { id: 5, parent_id: 4, visible: true }, { id: 6, parent_id: 4, visible: true }, { id: 7, parent_id: 3, visible: true }, { id: 8, parent_id: 2, visible: true } ]; const getNewArray = (id, items) => items.map(item => { if ([item.id, item.parent_id].includes(id)) { item.visible = false; } return item; }); console.log(getNewArray(4, array));
I would break apart the recursive code that finds the list of descendants from the code that does the data manipulation. Here’s one possibility:
const descendants = (array, root) => [ root, ...array .filter (({parent_id}) => parent_id == root) .flatMap (({id}) => descendants (array, id)) ] const changeBranch = (fn) => (array, root, keys = descendants (array, root)) => array .map (element => keys .includes (element .id) ? fn (element) : element) const makeInvisible = changeBranch ( ({visible, ...rest}) => ({...rest, visible: false}) ) const array = [{ id: 1, parent_id: 0, visible: true }, { id: 2, parent_id: 0, visible: true }, { id: 3, parent_id: 1, visible: true }, { id: 4, parent_id: 3, visible: true }, { id: 5, parent_id: 4, visible: true }, { id: 6, parent_id: 4, visible: true }, { id: 7, parent_id: 3, visible: true }, { id: 8, parent_id: 2, visible: true }]; console .log (makeInvisible (array, 4)) console .log (makeInvisible (array, 2))
.as-console-wrapper {min-height: 100% !important; top: 0}
descendants
finds the ids of the root id supplied and all the nodes descendant from it inside your array.
changeBranch
takes a function to transform a node and returns a function that takes an array and the root id and returns a new array containing either the result of applying that function (when the node is descendant from the root) or the original value (when it isn’t.)
makeInvisible
is the result of applying to changeBranch
a function which sets visible
to false
. This is the final function you’re looking for.
Note that if your list is cyclic and not hierarchical, this will not work. Your stack would likely overflow.