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 .
Advertisement
Answer
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);