Skip to content
Advertisement

How to list multi level Sub-categories under their Categories if all the catgories are in the same array of objects?

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);
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement