I'm working on dropdown menu of categories with sub-categories, and some sub-categories has sub-categories too.
i have array of categories with parent_id
property which comes from server and i want to create another array with my custom structure in client side.
parent_id : null
is for main category.
Categories array coming from server
const categories = [
{ id: "10001", name: "name1", parent_id: null },
{ id: "10002", name: "name2", parent_id: "10001" },
{ id: "10003", name: "name3", parent_id: "10001" },
{ id: "10004", name: "name4", parent_id: null },
{ id: "10005", name: "name5", parent_id: null },
{ id: "10006", name: "name6", parent_id: "10002" },
{ id: "10007", name: "name7", parent_id: "10002" },
{ id: "10008", name: "name8", parent_id: "10003" },
{ id: "10009", name: "name9", parent_id: "10004" },
]
My expecting result
const categories= [
{
id: "10001",
name: "name1",
subCategories: [
{
id: "10002",
name: "name2",
subCategories: [
{ id: "10006", name: "name6" },
{ id: "10007", name: "name7" },
],
},
{
id: "10003",
name: "name3",
subcategories: [{ id: "10008", name: "name8", parent_id: "10003" }],
},
],
},
{
id: "10004",
name: "name4",
subCategories: [{ id: "10009", name: "name9", parent_id: "10004" }],
},
{ id: "10005", name: "name5" , subCategories: [] },
]
My code
this code gives the lvl-1 and lvl-2 categories but we want all sub categories in any lvl.
const result = categories
.map((category, index, array) => {
if (category.parent_id === null) {
return {
...category,
subCategory: array.filter((cat) => cat.parent_id === category.id),
}
}
return null; // insert null in array
})
.filter((category) => category); // filter null items from array
// output
[
{
"id": "10001",
"name": "name1",
"parent_id": null,
"subCategory": [
{
"id": "10002",
"name": "name1",
"parent_id": "10001"
},
{
"id": "10003",
"name": "name1",
"parent_id": "10001"
}
]
},
{
"id": "10004",
"name": "name1",
"parent_id": null,
"subCategory": [
{
"id": "10009",
"name": "name1",
"parent_id": "10004"
}
]
},
{
"id": "10005",
"name": "name1",
"parent_id": null,
"subCategory": []
}
]
as you see these categories { id: "10006"}
,{ id: "10007"}
,{ id: "10008"}
are not here.
In this example we have only 3 lvl of sub-categories but it's possible to have even more lvl of sub-categories.
Thank you .
CodePudding user response:
You can loop over all categories that have a parent_id
, and assign them to their parent.
Then, in the original array, filter out all categories that have a parent.
let categories = [
{ id: "10001", name: "name1", parent_id: null },
{ id: "10002", name: "name2", parent_id: "10001" },
{ id: "10003", name: "name3", parent_id: "10001" },
{ id: "10004", name: "name4", parent_id: null },
{ id: "10005", name: "name5", parent_id: null },
{ id: "10006", name: "name6", parent_id: "10002" },
{ id: "10007", name: "name7", parent_id: "10002" },
{ id: "10008", name: "name8", parent_id: "10003" },
{ id: "10009", name: "name9", parent_id: "10004" },
];
categories
.filter(c => c.parent_id) // For all categories that have a parent,
.forEach(c => { // Assign them to that parent.
const parent = categories.find(p => p.id === c.parent_id);
parent.subCategories = parent.subCategories || [];
parent.subCategories.push(c);
});
// Now only give me categories that have no parent.
categories = categories.filter(c => !c.parent_id);
console.log(categories);