How to update value of nested array of objects
11,944
Solution 1
You could use an iterative and recursice approach with a named function as callback for Array#forEach
.
let mainArray = [
{
value: '/AG_TURF-123',
label: 'Ag & Turf',
checked: false,
id: 123,
children: [
{
value: '/AG_TURF-123/TRACTOR-456',
label: 'Tractors',
checked: false,
id: 456,
children: [
{
value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series',
label: 'Large (7, 8, 9) Series',
checked: false,
id: 789,
children: [
{
value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/7-family-tractor',
label: '7 Family Tractor',
checked: false,
id: 101112
},
{
value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/8-family-tractor',
label: '8 Family Tractor',
checked: false,
id: 131415
},
{
value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/9-family-tractor',
label: '9 Family Tractor',
checked: false,
id: 161718
}
]
},
{
value: '/app/Http/routes.js',
label: 'routes.js',
checked: false,
id: 181920
}
]
},
{
value: '/app/Providers',
label: 'Providers',
checked: false,
id: 212223,
children: [
{
value: '/app/Http/Providers/EventServiceProvider.js',
label: 'EventServiceProvider.js',
checked: false,
id: 242526
}
]
}
]
},
{
value: '/config',
label: 'config',
checked: false,
id: 272829,
children: [
{
value: '/config/app.js',
label: 'app.js',
checked: false,
id: 303132
},
{
value: '/config/database.js',
label: 'database.js',
checked: false,
id: 333435
}
]
},
{
value: '/public',
label: 'public',
checked: false,
id: 353637,
children: [
{
value: '/public/assets/',
label: 'assets',
checked: false,
id: 383940,
children: [
{
value: '/public/assets/style.css',
label: 'style.css',
checked: false,
id: 404142
}
]
},
{
value: '/public/index.html',
label: 'index.html',
checked: false,
id: 434445
}
]
},
{
value: '/.env',
label: '.env',
checked: false,
id: 464748
},
{
value: '/.gitignore',
label: '.gitignore',
checked: false,
id: 495051
},
{
value: '/README.md',
label: 'README.md',
checked: false,
id: 525354
}
],
ids = [525354, 123, 131415];
mainArray
.forEach(
function iter(a) {
if (ids.includes(a.id)) {
a.checked = true;
}
Array.isArray(a.children) && a.children.forEach(iter);
}
);
console.log(mainArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Solution 2
If your id
s are "unique" (there's only one unique object for each id
property), you could also split this action in to two steps:
- Make a new data structure that flattens all items in to one object of
id: item
- Loop through the
ids
to retrieve the items from this object.
If you find yourself looking up many objects by id
, it might be easier to create this interim representation.
The creation of the map uses recursion similar to the other answer: whenever an item
contains a children
array, it adds those to the map object before it returns.
const mainArray = [{ value: '/AG_TURF-123', label: 'Ag & Turf', checked: false, id: 123, children: [{ value: '/AG_TURF-123/TRACTOR-456', label: 'Tractors', checked: false, id: 456, children: [{ value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series', label: 'Large (7, 8, 9) Series', checked: false, id: 789, children: [{ value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/7-family-tractor', label: '7 Family Tractor', checked: false, id: 101112 }, { value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/8-family-tractor', label: '8 Family Tractor', checked: false, id: 131415 }, { value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/9-family-tractor', label: '9 Family Tractor', checked: false, id: 161718 }] }, { value: '/app/Http/routes.js', label: 'routes.js', checked: false, id: 181920 }] }, { value: '/app/Providers', label: 'Providers', checked: false, id: 212223, children: [{ value: '/app/Http/Providers/EventServiceProvider.js', label: 'EventServiceProvider.js', checked: false, id: 242526 }] }] }, { value: '/config', label: 'config', checked: false, id: 272829, children: [{ value: '/config/app.js', label: 'app.js', checked: false, id: 303132 }, { value: '/config/database.js', label: 'database.js', checked: false, id: 333435 }] }, { value: '/public', label: 'public', checked: false, id: 353637, children: [{ value: '/public/assets/', label: 'assets', checked: false, id: 383940, children: [{ value: '/public/assets/style.css', label: 'style.css', checked: false, id: 404142 }] }, { value: '/public/index.html', label: 'index.html', checked: false, id: 434445 }] }, { value: '/.env', label: '.env', checked: false, id: 464748 }, { value: '/.gitignore', label: '.gitignore', checked: false, id: 495051 }, { value: '/README.md', label: 'README.md', checked: false, id: 525354 }];
// We reduce the array of nested items in to one object of:
// { id: item }
const idMap = mainArray.reduce(function merge(map, node) {
map[node.id] = node;
if (Array.isArray(node.children)) {
node.children.reduce(merge, map);
}
return map;
}, {});
const ids = [525354, 123, 131415];
// Whenever you need an item, you can get it
// using idMap[id]
const items = ids.map(id => idMap[id]);
items.forEach(item => item.checked = true);
// or: ids.forEach(id => idMap[id].checked = true)
Author by
Hashir Hussain
Updated on June 05, 2022Comments
-
Hashir Hussain almost 2 years
This is my actual array :
let mainArray= [ { value: '/AG_TURF-123', label: 'Ag & Turf', checked: false, id:123, children: [ { value: '/AG_TURF-123/TRACTOR-456', label: 'Tractors', checked: false, id:456, children: [ { value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series', label: 'Large (7, 8, 9) Series', checked: false, id:789, children: [{ value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/7-family-tractor', label: '7 Family Tractor', checked: false, id:101112 },{ value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/8-family-tractor', label: '8 Family Tractor', checked: false, id:131415 },{ value: '/AG_TURF-123/TRACTOR-456/Large-7-8-9-series/9-family-tractor', label: '9 Family Tractor', checked: false, id:161718 }], }, { value: '/app/Http/routes.js', label: 'routes.js', checked: false, id:181920 }, ], }, { value: '/app/Providers', label: 'Providers', checked: false, id:212223, children: [{ value: '/app/Http/Providers/EventServiceProvider.js', label: 'EventServiceProvider.js', checked: false, id:242526 }], }, ], }, { value: '/config', label: 'config', checked: false, id:272829, children: [ { value: '/config/app.js', label: 'app.js', checked: false, id:303132 }, { value: '/config/database.js', label: 'database.js', checked: false, id:333435 }, ], }, { value: '/public', label: 'public', checked: false, id:353637, children: [ { value: '/public/assets/', label: 'assets', checked: false, id:383940, children: [{ value: '/public/assets/style.css', label: 'style.css',checked: false, id:404142 }], }, { value: '/public/index.html', label: 'index.html', checked: false, id: 434445 }, ], }, { value: '/.env', label: '.env', checked: false, id: 464748 }, { value: '/.gitignore', label: '.gitignore', checked: false, id: 495051 }, { value: '/README.md', label: 'README.md', checked: false, id: 525354 }, ];
This is my list of value :
const ids=[525354,123,131415];
I want to set
checked
totrue
if id matched. My main array may go to 6 to 7 step deep.What I've done till yet :
setCheckedFlagToItems(checkList, items) { return items.map((item) => { const node = item; if (checkList.indexOf(node.id) !== -1) { node.checked = true; } if ((node.children) && (Array.isArray(node.children) && node.children.length > 0)) { this.setCheckedFlagToItems(checkList, node.children); } return node; }, this); }
But it not working as usual.