5

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'
      }
    ],
    
  };

2 Answers 2

7

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. You are great. It really solved my doubt and also learnt how to do it. Thanks again.
for what its worth, if using Typescript, use const [menuAnchorEl, setMenuAnchorEl] = useState<null | Record<string, HTMLElement>>(null)
1

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

1 Comment

basically the same solution but in a simplified example 👍🏼

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.