shiva
shiva

Reputation: 51

how to handle multiple popover (material ui)

I tried to use multiple popover within a component. For ex, in below code I have two popovers, but when clicking any of the two button, both the popovers are opened. How can we handle the onclick to open corresponding popover?

const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
    const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
        setAnchorEl(event.currentTarget);
    };

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

<Tabs variant="fullWidth" value={value} onChange={onNavChange} indicatorColor="transparent">
                        <Tab label="Menu 1" className={classes.navTab} component={Link} to="./Menu1"></Tab>
                        <Tab label="Menu 2" onClick={handleClick} aria-describedby="menu2Popover" aria-haspopup="true"></Tab>
                        <Tab label="Menu 3" component={Link} to="./Menu3"></Tab>
                        <Tab label="Menu 4"onClick={handleClick} aria-describedby="menu4Popover" aria-haspopup="true"></Tab>
                    </Tabs>
                    <Popover 
                        id="menu2Popover" open={Boolean(anchorEl)} onClose={handleClose}
                        anchorEl = {anchorEl}
                        anchorOrigin={{
                            vertical: 'top',
                            horizontal: 'left',
                        }}
                        transformOrigin={{
                            vertical: 'bottom',
                            horizontal: 'left',
                        }}>
                        <MenuList>
                            <MenuItem>Submenu 1</MenuItem>
                            <MenuItem>Submenu 2</MenuItem>
                        </MenuList>
                    </Popover>
                    <Popover 
                        id="menu4Popover" open={Boolean(anchorEl)} onClose={handleClose}
                        anchorEl = {anchorEl}
                        anchorOrigin={{
                            vertical: 'top',
                            horizontal: 'left',
                        }}
                        transformOrigin={{
                            vertical: 'bottom',
                            horizontal: 'left',
                        }}>
                        <MenuList>
                            <MenuItem>Submenu 3</MenuItem>
                            <MenuItem>Submenu 4</MenuItem>
                        </MenuList>
                    </Popover>

Upvotes: 5

Views: 12151

Answers (3)

U-Y
U-Y

Reputation: 1

You just need to give separate placeholder for popoverContent like "name + index", which is unique and sends the index as id in the handler function and set it in state then in open check is

index == your state where id is stored.

it will solve your problem.

  • step 01
const [id,setId] = useState(null)
  • step 02
const handleDropDown = (index) => {
setId(index)
}
  • step 03
<Popover placement="bottom" open={index == id} handler={() => handleDropDown(index)}>
  • step 04
<PopoverContent placeholder={`name-${index}`}>

Upvotes: 0

Klaus
Klaus

Reputation: 1220

You need to use different anchorEl's for each Popover:

import * as React from "react";
import { render } from "react-dom";
import { MenuList, MenuItem, Popover, Tabs, Tab } from "@material-ui/core";

import "./styles.css";

interface CustomMenuItem {
  anchorEl: null | HTMLElement;
  child: any;
}

function Popover1() {
  return (
    <MenuList>
      <MenuItem>Submenu 1</MenuItem>
      <MenuItem>Submenu 2</MenuItem>
    </MenuList>
  );
}

function Popover2() {
  return (
    <MenuList>
      <MenuItem>Submenu 3</MenuItem>
      <MenuItem>Submenu 4</MenuItem>
    </MenuList>
  );
}

function App() {
  const [popover1, setPopover1] = React.useState<CustomMenuItem>({
    anchorEl: null,
    child: <Popover1 />
  });
  const [popover2, setPopover2] = React.useState<CustomMenuItem>({
    anchorEl: null,
    child: <Popover2 />
  });

  return (
    <div className="App">
      <Tabs variant="fullWidth" indicatorColor="transparent">
        <Tab label="Menu 1" />
        <Tab
          value="Tab2"
          label="Menu 2"
          onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
            setPopover1({ ...popover1, anchorEl: event.currentTarget })
          }
          aria-describedby="menu2Popover"
          aria-haspopup="true"
        />
        <Tab label="Menu 3" />
        <Tab
          label="Menu 4"
          onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
            setPopover2({ ...popover2, anchorEl: event.currentTarget })
          }
          aria-describedby="menu4Popover"
          aria-haspopup="true"
        />
      </Tabs>

      <Popover
        id="menu2Popover"
        open={Boolean(popover1.anchorEl)}
        onClose={() => setPopover1({ ...popover1, anchorEl: null })}
        anchorEl={popover1.anchorEl}
        anchorOrigin={{
          vertical: "top",
          horizontal: "left"
        }}
        transformOrigin={{
          vertical: "bottom",
          horizontal: "left"
        }}
      >
        {popover1.child}
      </Popover>
      <Popover
        id="menu4Popover"
        open={Boolean(popover2.anchorEl)}
        onClose={() => setPopover2({ ...popover2, anchorEl: null })}
        anchorEl={popover2.anchorEl}
        anchorOrigin={{
          vertical: "top",
          horizontal: "left"
        }}
        transformOrigin={{
          vertical: "bottom",
          horizontal: "left"
        }}
      >
        {popover2.child}
      </Popover>
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Look at the codesandbox. If you have any further questions let me know and I can update my answer.

Upvotes: 4

Babak Yaghoobi
Babak Yaghoobi

Reputation: 1985

another sample with one Popover

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import AppBar from "@material-ui/core/AppBar";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Popover from "@material-ui/core/Popover";
import MenuList from "@material-ui/core/MenuList";
import MenuItem from "@material-ui/core/MenuItem";

const styles = theme => ({
  root: {
    flexGrow: 1,
    backgroundColor: theme.palette.background.paper,
    textTransform: "none"
  }
});

class SimpleTabs extends React.Component {
  state = {
    value: 0,
    anchorEl: null,
    popno: -1
  };

  handlePopoverClose = () => {
    this.setState({ anchorEl: null, popno: -1 });
  };

  handleClick = (e, _popno) => {
    this.setState({ anchorEl: e.currentTarget, popno: _popno });
  };

  handleChange = (event, value) => {
    this.setState({ value });
  };

  render() {
    const { classes } = this.props;
    const { value } = this.state;

    return (
      <div className={classes.root}>
        <AppBar position="static">
          <Tabs value={value} onChange={this.handleChange}>
            <Tab label="Tab 1" onClick={e => this.handleClick(e, 1)} />
            <Tab label="Tab 2" onClick={e => this.handleClick(e, 2)} />
            <Tab label="Tab 3" onClick={e => this.handleClick(e, 3)} />
          </Tabs>
          <Popover
            id="menu2Popover"
            open={this.state.anchorEl !== null}
            onClose={this.handlePopoverClose}
            anchorEl={this.state.anchorEl}
          >
            {this.state.popno === 1 && (
              <MenuList>
                <MenuItem>Tab 1 - Submenu 1</MenuItem>
                <MenuItem>Tab 1 - Submenu 2</MenuItem>
              </MenuList>
            )}
            {this.state.popno === 2 && (
              <MenuList>
                <MenuItem>Tab 2 - Submenu 1</MenuItem>
                <MenuItem>Tab 2 - Submenu 2</MenuItem>
              </MenuList>
            )}
            {this.state.popno === 3 && (
              <MenuList>
                <MenuItem>Tab 3 - Submenu 1</MenuItem>
                <MenuItem>Tab 3 - Submenu 2</MenuItem>
              </MenuList>
            )}
          </Popover>
        </AppBar>
      </div>
    );
  }
}

export default withStyles(styles)(SimpleTabs);

answer output https://codesandbox.io/s/material-tabs-demo-tpugw

Upvotes: 1

Related Questions