Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter a JavaScript deeply nested array of objects based on its values

I have a menu structure as follows:

const menu = [
  {
    title: 'Supervisor Dashboard',
    link: '/dashboard/supervisor-dashboard',
    slug: '/dashboard/supervisor-dashboard'
  },
  {
    title: 'User Dashboard',
    link: '/dashboard/user-dashboard',
    slug: '/dashboard/user-dashboard'
  },
  {
    title: 'Inventory',
    slug: '/inventory',
    children: [
      {
        title: 'Add Inventory',
        link: '/inventory/add-inventory',
        slug: '/inventory/add-inventory'
      },
      {
        title: 'Remove Inventory',
        link: '/inventory/remove-inventory',
        slug: '/inventory/remove-inventory'
      },
    ]
  },
  {
    title: 'Membership',
    slug: '/membership',
    children: [
      {
        title: 'Program A',
        slug: '/membership/program-a',
        children: [
          {
            title: 'View Membership',
            link: '/membership/program-a/view',
            slug: '/membership/program-a/view'
          },
          {
            title: 'Add Membership',
            link: '/membership/program-a/add',
            slug: '/membership/program-a/add'
          },
          {
            title: 'Delete Membership',
            link: '/membership/program-a/delete',
            slug: '/membership/program-a/delete'
          }
        ]
      },
      {
        title: 'Program B',
        slug: '/membership/program-b',
        children: [
          {
            title: 'View Membership',
            link: '/membership/program-b/view',
            slug: '/membership/program-b/view'
          },
          {
            title: 'Add Membership',
            link: '/membership/program-b/add',
            slug: '/membership/program-b/add'
          },
          {
            title: 'Delete Membership',
            link: '/membership/program-b/delete',
            slug: '/membership/program-b/delete'
          }
        ]
      }
    ],
  },
];

I want to filter the menu i.e showing only whatever granted to the user. The user can only view the menu based on allowed slugs as follows:

const allowed_slug = [
  '/dashboard/user-dashboard',
  '/inventory/add-inventory',
  '/membership/program-b/view',
  '/membership/program-b/add'
];

Using .filter I am able to filter the 1st layer of the array. Here's what I achieved so far:

function filterMenu(menus, allowed_slug) {
  const result = menus.filter(function (menu_item) {
    return allowed_slug.filter(function(slug) {
      return menu_item.slug.indexOf(slug) > -1;
    }).length;
  });

  return result;
}

Ideal output should look like this:

o
|-- User Dashboard
|-- Inventory
|   `-- Add Inventory
`-- Membership
    `-- Program B
        |-- View Membership
        `-- Add Membership

The problem is, I cannot filter the nested array i.e. children & children of children. Any help is very much appreciated. :)

like image 344
MyWebDev Avatar asked Dec 14 '22 12:12

MyWebDev


1 Answers

You could check if one allowdSlug starts with a slug of the actual object.

var menus = [{ title: 'Supervisor Dashboard', link: '/dashboard/supervisor-dashboard', slug: '/dashboard/supervisor-dashboard' }, { title: 'User Dashboard', link: '/dashboard/user-dashboard', slug: '/dashboard/user-dashboard' }, { title: 'Inventory', slug: '/inventory', children: [{ title: 'Add Inventory', link: '/inventory/add-inventory', slug: '/inventory/add-inventory' }, { title: 'Remove Inventory', link: '/inventory/remove-inventory', slug: '/inventory/remove-inventory' }] }, { title: 'Membership', slug: '/membership', children: [{ title: 'Program A', slug: '/membership/program-a', children: [{ title: 'View Membership', link: '/membership/program-a/view', slug: '/membership/program-a/view' }, { title: 'Add Membership', link: '/membership/program-a/add', slug: '/membership/program-a/add' }, { title: 'Delete Membership', link: '/membership/program-a/delete', slug: '/membership/program-a/delete' }] }, { title: 'Program B', slug: '/membership/program-b', children: [{ title: 'View Membership', link: '/membership/program-b/view', slug: '/membership/program-b/view' }, { title: 'Add Membership', link: '/membership/program-b/add', slug: '/membership/program-b/add' }, { title: 'Delete Membership', link: '/membership/program-b/delete', slug: '/membership/program-b/delete' }] }] }], allowed_slug = ['/dashboard/user-dashboard', '/inventory/add-inventory', '/membership/program-b/view', '/membership/program-b/add'],
    filter = menus => menus
        .filter(({ slug }) => allowed_slug.some(s => s.startsWith(slug)))
        .map(({ title, slug, children = [] }) => {
            children = filter(children);
            return Object.assign({ title, slug }, children.length && { children })
        }),
    result = filter(menus);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 122
Nina Scholz Avatar answered Dec 21 '22 10:12

Nina Scholz