Praveen Kumar
Praveen Kumar

Reputation: 88

Handling multiple MenuItems in material-ui React

enter image description herePlease help me with this multiple menu handling events. I have dynamic menus and its corresponding menuitems in a json. I wanted to show menuitems declared under that particular parent menu, instead it is overlapping and showing all of the parents menuitems when a single menu button is clicked. This is my Nvbar.js

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Toolbar from '@material-ui/core/Toolbar';
import Button from '@material-ui/core/Button';
import { InputData } from '../InputJSON';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';


const useStyles = makeStyles((theme) => ({
  root: {
    flexGrow: 1,
  },
  navButton: {
    margin: 'auto',
  },
  title: {
    flexGrow: 1,
  },
  toolbar:{
    backgroundColor: "orange",
  },
}));



export default function ButtonAppBar() {
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState(null);

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div className={classes.root}>
        <Toolbar className={classes.toolbar}>
          {Object.keys(InputData).map((item, index) => (
              <div 
                className={classes.navButton}
                key={index}
              >
                <Button 
                  color="inherit"
                  onClick={handleClick}
                >
                  {item} <i className='fas fa-caret-down' />
                </Button>
                <Menu
                  anchorEl={anchorEl}
                  keepMounted
                  open={Boolean(anchorEl)}
                  onClose={handleClose}
                  getContentAnchorEl={null}
                  anchorOrigin={{vertical: 'bottom', horizontal: 'center'}}
                  transformOrigin={{vertical: 'top', horizontal: 'center'}}
                >
                  {InputData[item].map((menuitems, menuindex) =>
                     (
                        <MenuItem
                          key={menuindex}
                          selected={menuitems === item}
                          onClick={handleClose}
                        >
                          {menuitems.title}
                        </MenuItem>

                    )
                  )}
                </Menu>
                
              </div>
            ))
          }
        </Toolbar>
    </div>
  );
}

InputData.js

export const MenuItems = 
  {"furniture": 
    [
      {
        title: 'Marketing',
        path: '/marketing',
        cName: 'dropdown-link'
      },
      {
        title: 'Consulting',
        path: '/consulting',
        cName: 'dropdown-link'
      },
      {
        title: 'Design',
        path: '/design',
        cName: 'dropdown-link'
      },
      {
        title: 'Development',
        path: '/development',
        cName: 'dropdown-link'
      }
    ],  
    "mobiles": 
    [
      {
        title: 'iphone',
        path: '/marketing',
        cName: 'dropdown-link'
      },
      {
        title: 'samsung',
        path: '/consulting',
        cName: 'dropdown-link'
      },
      {
        title: 'oneplus',
        path: '/design',
        cName: 'dropdown-link'
      },
      {
        title: 'sony',
        path: '/development',
        cName: 'dropdown-link'
      }
    ],
    "laptops": 
    [
      {
        title: 'iphone',
        path: '/marketing',
        cName: 'dropdown-link'
      },
      {
        title: 'samsung',
        path: '/consulting',
        cName: 'dropdown-link'
      },
      {
        title: 'oneplus',
        path: '/design',
        cName: 'dropdown-link'
      },
      {
        title: 'sony',
        path: '/development',
        cName: 'dropdown-link'
      }
    ],
    "aircon": 
    [
      {
        title: 'iphone',
        path: '/marketing',
        cName: 'dropdown-link'
      },
      {
        title: 'samsung',
        path: '/consulting',
        cName: 'dropdown-link'
      },
      {
        title: 'oneplus',
        path: '/design',
        cName: 'dropdown-link'
      },
      {
        title: 'sony',
        path: '/development',
        cName: 'dropdown-link'
      }
    ],
    "kitapp": 
    [
      {
        title: 'iphone',
        path: '/marketing',
        cName: 'dropdown-link'
      },
      {
        title: 'samsung',
        path: '/consulting',
        cName: 'dropdown-link'
      },
      {
        title: 'oneplus',
        path: '/design',
        cName: 'dropdown-link'
      },
      {
        title: 'sony123',
        path: '/development',
        cName: 'dropdown-link'
      }
    ],
    
  };

Upvotes: 5

Views: 4412

Answers (2)

Mohammed Yousuff
Mohammed Yousuff

Reputation: 326

Thanks @ericgio, Your solution worked like magic.

Hello every if someone dropped in here for table rows having similar dropdown in loop and repeating as per number of rows, please check my code below it would help saving your time.

Table rows containing same dropdown of content which had similar options, just made small changes as suggested and code is working as expected. my code changes are listed below.

UseState

const [actionDD, setActionDD] = useState(null)

for toggle dropdown

const actionDropdown = (index, e) => {
 setActionDD({ [index]: e.currentTarget })
}

Button

<IconButton
  onClick={e => {
  actionDropdown(index, e)
  }}
  ...other attributes
>
  <MoreVertIcon />
</IconButton>

Inside Menu

<Menu
  anchorEl={actionDD && actionDD[index]}
  open={actionDD && Boolean(actionDD[index])}
  ...other attributes
 >
  <MenuItem >1</MenuItem>
  <MenuItem >2</MenuItem>
  <MenuItem >3</MenuItem>
</Menu>

Thank you all, Special thanks to @ericgio

Upvotes: 1

ericgio
ericgio

Reputation: 3519

You need to track each anchor element separately, according to which menu item has been clicked. You can do this by setting the element according to the item key:

export default function ButtonAppBar() {
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState(null);

  // Instead of tracking a single element, set the element according to
  // the menu item's index.
  const handleClick = (index, event) => {
    setAnchorEl({ [index]: event.currentTarget });
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div className={classes.root}>
      <Toolbar className={classes.toolbar}>
        {Object.keys(InputData).map((item, index) => (
          <div className={classes.navButton} key={index}>
            <Button color="inherit" onClick={(e) => handleClick(index, e)}>
              {item} <i className="fas fa-caret-down" />
            </Button>
            <Menu
              anchorEl={
                // Check to see if the anchor is set.
                anchorEl && anchorEl[index]
              }
              keepMounted
              open={
                // Likewise, check here to see if the anchor is set.
                Boolean(anchorEl && anchorEl[index])
              }
              onClose={handleClose}
              getContentAnchorEl={null}
              anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
              transformOrigin={{ vertical: "top", horizontal: "center" }}
            >
              {menuItems[item].map((menuitems, menuindex) => (
                <MenuItem
                  key={menuindex}
                  selected={menuitems === item}
                  onClick={handleClose}
                >
                  {menuitems.title}
                </MenuItem>
              ))}
            </Menu>
          </div>
        ))}
      </Toolbar>
    </div>
  );
}

Working sandbox: https://codesandbox.io/s/icy-haze-h0594

Upvotes: 6

Related Questions