Home > OS >  Dynamic menu based on locations from array of arrays
Dynamic menu based on locations from array of arrays

Time:01-06

I'm trying to generate a dynamic menu based on locations provided in an array of arrays.

What I'm trying to achieve:

Menu structure like this:

Location 1
  |_ sub-location 1
  |_ sub-location 2
      |_ floor 1
      |_ floor 2
Location 2
  |_ sub-location 1

etc, etc. The menu has to be dynamic as I do not know before hand which locations will be present.

The locations are provided in an array of arrays. Each array in the array contains the full path for a location, e.g.

[
  ["Location 1"],
  ["Location 1", "sub-location 1"],
  ["Location 1", "sub-location 2", "floor 1"]
  ["Location 1", "sub-location 2", "floor 2"]
]

In many cases, there will be duplicates.

I'm trying to come up with some smart way of condensing this down to some way of rendering it with React. I'm using a Menu component from Antd.

I'm struggling with getting an array to fit the model, as I don't see how to structure it in a way that allows for some arbitrary number of sub-menus and menu items.

Could it in some way be made into an object or something similar? Still pretty new to React and javascript.

If anyone could provide some guidance, it would be super helpful!

CodePudding user response:

This structure might be more understandable and easy to work with.

{
    name: 'Location 1',
    sub: [
        {
            name: 'sub-location 1',
            sub: [
                { name: 'floor 1' },
                { name: 'floor 2' },
            ]
        }
    ]
}

Let's call the above structure a single menuItem. Now you can have an array of menus like so

const menuItems = [menuItem1, menuItem2, ....]

Use this code to transform your data

const badMenu = [
    ['Location 1'],
    ['Location 1', 'sub-location 1'],
    ['Location 1', 'sub-location 2', 'floor 1'],
    ['Location 1', 'sub-location 2', 'floor 2'],
    ['Location 2', 'sub-location 2', 'floor 2'],
    ['Location 2', 'sub-location 2', 'floor 2'],
];

const func = (array, menu) => {
    const name = array[0];
    if (!name) {
        return;
    }

    let selected = menu.find((menuItem) => menuItem.name == name);

    if (!selected) {
        selected = { name, sub: [] };
        menu.push(selected);
    }

    func(array.slice(1), selected.sub);
};

let newMenu = [];

for (let i = 0; i < badMenu.length; i  ) {
    const menuList = badMenu[i];
    func(menuList, newMenu);
}

console.log(JSON.stringify(newMenu, null, 4));

To render this menu using antd:

const renderMenu = (menu, i) => {
    if (menu.sub && menu.sub.length) {
        return (
            <Menu.SubMenu key={menu.name   i} title={menu.name}>
                {menu.sub.map(renderMenu)}
            </Menu.SubMenu>
        );
    }
    return <Menu.Item key={menu.name   i}>{menu.name}</Menu.Item>;
};

function App() {
    return <Menu>{menu.map(renderMenu)}</Menu>;
}
  •  Tags:  
  • Related