Reputation: 15
I'm still learning the ropes of recursion, and I would like to add 'isChecked: false' to every object in this nested tree of arrays.
const nestedMap = (arr) => {
const result = arr.map(row => {
if (row.children.length) {
const children = row.children.map(child => {
return { ...child, isChecked: false };
});
return { ...row, isChecked: false, children };
} else {
return { ...row, isChecked: false };
}
});
return result[0].children[0]
}
nestedMap([{title: 'page1', children: [{title: 'page2', children: [{title: 'page4'}]}, {title: 'page3'}]}, {title: 'page5', children: []}])
Here's my result - as you can see I'm successfully updating the first set of children, but not the rest.
{ title: 'page2',
children: [ { title: 'page4' } ],
isChecked: false }
I know I'm supposed to call the function somewhere inside itself, but I'm an idiot. As always, any help would be greatly appreciated. Thank you.
Upvotes: 1
Views: 681
Reputation: 50797
Another possibility is to write a more generic nestedMap
implementation, and then pass it a function which adds your property. Here's how I might write it:
const nestedMap = (fn) => (xs) =>
xs .map (({children, ...rest}) => fn ({
... rest,
... (children ? {children: nestedMap (fn) (children)} : {})
}))
const addProp = (key, val) => (obj) =>
({... obj, [key]: val})
const pages = [{title: 'page1', children: [{title: 'page2', children: [{title: 'page4'}]}, {title: 'page3'}]}, {title: 'page5', children: []}]
console .log (
nestedMap (addProp ('checked', false)) (pages)
)
This version does not mutate our original, but creates a new array full of new objects. (It does not do a full clone; other properties of our nodes may be shared by reference.)
addProp
is simple enough: it takes a key and a value and returns a function which takes an object, returning a new object with all its properties and the new key/value.
nestedMap
recursively maps a function over a node: {..., children: [more nodes]}
structure. The transformation function supplied to it is called first (recursively) on the children of each node and then on the node itself.
Upvotes: 1
Reputation: 6805
Your if-statement if (row.children.length) {
checks if row.children
is an array with length > 0, so here's where you'd want to call nestedMap
again.
Try something like this:
const nestedMap = (arr) => {
const result = arr.map(row => {
// check if row.children exists AND if its length exists / is greater than 0
if (row.children && row.children.length) {
const children = nestedMap(row.children);
return { ...row, isChecked: false, children };
} else {
return { ...row, isChecked: false };
}
});
// Note: You should probably return the entire result here, not result[0].children[0]
return result;
}
let output = nestedMap([{title: 'page1', children: [{title: 'page2', children: [{title: 'page4'}]}, {title: 'page3'}]}, {title: 'page5', children: []}])
console.log(output)
Notice I made 3 changes:
if (row.children && row.children.length) {
row.children
exists, before checking row.children.length
const children = nestedMap(row.children);
return result;
isChecked: false
in every object).result[0].children[0]
, which will only return the original array's first item's first child?Upvotes: 2