MUI Popover not anchoring properly (AnchorEl, React, material-table, MUI)
Asked Answered
S

1

7

I've looked through many questions regarding popover anchoring, but I haven't seen any when using a MaterialTable element from the material-table library: https://github.com/mbrn/material-table .

While debugging it looks like the anchorEl properly holds the button reference, but it seems to rerender a second time and loses the reference. From what I can tell this is from the button being remounted. So the final rendering puts the popover in the top left corner of the screen by default. I'm wondering if anyone has found a way to either prevent this remount or some other workaround.

export class UsersList extends Component {
constructor(props) {
super(props);
this.state = {
  anchorEl: null,
  anchorReference: "anchorEl"
};
}



render() {
const { classes } = this.props;
var { anchorEl } = this.state;
const open = Boolean(anchorEl);
return (
  <MaterialTable
    isLoading={this.state.isLoading}
    columns={[
      { title: "Username", field: "username" },
      ...more columns
    ]}
    data={this.state.users}
    onRowClick={(evt, selectedRow) => this.setState({ selectedRow })}


    //where I update my anchorEl on a click on the "edit" icon
    actions={[
      {
        icon: "edit",
        tooltip: "Edit",
        onClick: (event, rowData) => {
            this.setState({ anchorEl: event.currentTarget });
          }
        },
      },
    ]}

    components={{
      Body: props => (
        <React.Fragment>
          <MTableBody {...props} />
          <Popover
                //a breakpoint here is hit twice. First time with valid ref, second time without ref
                getContentAnchorEl={null}
                id="myId"
                open={open}
                onClose={this.handlePopoverClose.bind(this)}
                anchorEl={anchorEl}
                getContentAnchorEl={null}
                anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
                transformOrigin={{ vertical: "top", horizontal: "center" }}
                open={open}
              >
                <Typography>The content of the Popover.</Typography>
              </Popover>

EDIT** codesandbox running example: If you click on the edit column row item a popup shows up in the top left hand of the screen instead of next to the rowitem: https://codesandbox.io/s/loving-tdd-8r910?file=/src/App.js

Snowwhite answered 27/4, 2020 at 19:36 Comment(4)
Your code is not complete and it's impossible to run/guess what exactly is the problem. Please take the time to create a reproducible working example (you can use codesandbox.io for that) and explain what is the issue.Amena
@Amena sorry about that, added the exampleSnowwhite
@Snowwhite have you get solution?Recrement
I've also been having problems with this. The anchorEl needs to be in the same component as the popover (it is). When the anchor exists in a child component, calling the parent to update the anchor will then re-render the children (the rows in the material-table). I tried useMemo but I don't think you can avoid material-table itself from re-rendering. The anchor will never be correct and you'll get a warning in the console and a popover in the top left corner.Schwitzer
I
3

Move popover to a separate component so that anchorEl would be in the same component as Popover. Example with menu:

function MenuCell() {
  const [anchorEl, setAnchorEl] = useState(null);

  return (
    <div>
      <IconButton
        aria-label="more"
        aria-haspopup="true"
        onClick={(event) => setAnchorEl(event.currentTarget)}
      >
        <MoreVertIcon />
      </IconButton>
      <Menu
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={() => setAnchorEl(null)}
      >
        <MenuItem selected={false} onClick={() => setAnchorEl(null)}>
          Item 1
        </MenuItem>
        <MenuItem selected={false} onClick={() => setAnchorEl(null)}>
          Item 2
        </MenuItem>
        <MenuItem selected={false} onClick={() => setAnchorEl(null)}>
          Item 3
        </MenuItem>
      </Menu>
    </div>
  )
}

And use in Column cell definition:

function CustomTable() {
  
  const menuColumn = {
    id: 'menus',
    Header: '',
    Cell: ({ row }) => <MenuCell row={row} />,
  };

  // ...
}
Indistinguishable answered 14/6, 2021 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.