Incorporating a Menu within a TableCell using Material-UI

I have a desire to incorporate Google's Material UI Menu Item inside a TableCell, following their documentation guidelines here in this illustration:

https://i.stack.imgur.com/IffEM.png

This is my current method:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import {
  Grid,
  IconButton,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  Paper,
  Menu,
  MenuItem,
  Button,
} from '@material-ui/core';
import { ExpandLess, ExpandMore } from '@material-ui/icons';

const styles = theme => ({});

const Questions = ({ data, classes, openMenu, anchorEls, handleClose }) => {
  const CustomTableCell = withStyles(theme => ({
    head: {
      backgroundColor: theme.palette.common.black,
      color: theme.palette.common.white,
    },
    body: {
      fontSize: 14,
    },
  }))(TableCell);

  const formatData = rawData => Object.keys(rawData).map(key => rawData[key]);

  const n = { key: 'hi', rating: 55, text: 'wassup' };

  return (
    <Grid container alignItems={'center'} direction={'column'} spacing={8}>
      <Paper className={classes.root}>
        <Button
          key="close"
          aria-label="Close"
          color="inherit"
          className={classes.close}
          onClick={e => openMenu('dude', e)}
        >
          <ExpandMore />
        </Button>
        <Menu
          id={`dude`}
          key="menu"
          anchorEl={anchorEls.dude}
          open={Boolean(anchorEls.dude)}
          onClose={e => handleClose('dude', e)}
        >
          <MenuItem onClick={e => handleClose('dude', e)}>Delete</MenuItem>
          <MenuItem onClick={e => handleClose('dude', e)}>Flag</MenuItem>
          <MenuItem onClick={e => handleClose('dude', e)}>
            Mark Answered
          </MenuItem>
        </Menu>
        <Table className={classes.table}>
          <TableHead>
            <TableRow>
              <CustomTableCell>Question</CustomTableCell>
              <CustomTableCell numeric>Rating</CustomTableCell>
              <CustomTableCell>Upvote</CustomTableCell>
              <CustomTableCell>Downvote</CustomTableCell>
              <CustomTableCell>Options</CustomTableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            <TableRow className={classes.row} key={n.key}>
              <CustomTableCell component="th" scope="row">
                {n.text}
              </CustomTableCell>
              <CustomTableCell numeric>{n.rating}</CustomTableCell>
              <CustomTableCell>
                <IconButton
                  key="close"
                  aria-label="Close"
                  color="inherit"
                  className={classes.close}
                  onClick={() => ''}
                >
                  <ExpandLess />
                </IconButton>
              </CustomTableCell>
              <CustomTableCell>
                <IconButton
                  key="close"
                  aria-label="Close"
                  color="inherit"
                  className={classes.close}
                  onClick={() => ''}
                >
                  <ExpandMore />
                </IconButton>
              </CustomTableCell>
              <CustomTableCell>
                <Button
                  key="close"
                  aria-label="Close"
                  color="inherit"
                  className={classes.close}
                  onClick={e => openMenu(n.key, e)}
                >
                  <ExpandMore />
                </Button>
                <Menu
                  id={`simple-menu-${n.key}`}
                  key="menu"
                  anchorEl={anchorEls[n.key]}
                  open={Boolean(anchorEls[n.key])}
                  onClose={e => handleClose(n.key, e)}
                >
                  <MenuItem onClick={e => handleClose(n.key, e)}>
                    Delete
                  </MenuItem>
                  <MenuItem onClick={e => handleClose(n.key, e)}>dude</MenuItem>
                  <MenuItem onClick={e => handleClose(n.key, e)}>choc</MenuItem>
                </Menu>
              </CustomTableCell>
            </TableRow>
          </TableBody>
        </Table>
      </Paper>
    </Grid>
  );
};

Questions.propTypes = {
  data: PropTypes.object.isRequired,
  anchorEls: PropTypes.object.isRequired,
  classes: PropTypes.object.isRequired,
  openMenu: PropTypes.func.isRequired,
  handleClose: PropTypes.func.isRequired,
};

Questions.defaultProps = {};

export default withStyles(styles)(Questions);

Although it is functional, the menu is not displaying in the correct position even when passing the related event e. I inserted a dummy element before the table for testing purposes and found that the dummy worked correctly, as shown in the screenshot below. https://i.stack.imgur.com/zrGKi.png

Meanwhile, the improperly positioned menu from the button in the table can be seen here: https://i.stack.imgur.com/0iDMW.png

Any suggestions on what might be causing this issue? It seems like the context and anchorEl are not accurately identifying the location on the page, but I'm unsure about how to address it.

Answer №1

There seems to be an issue in your openMenu function that needs to be addressed. Make sure to set the event target correctly in the openMenu function and set it to null in the handleClose function. To better illustrate this, here's a simple example for you:

class ExampleList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            items: [],
            anchorElements: []
        }
    }
    handleItemClick = (id, event) => {
        let { anchorElements } = this.state;
        anchorElements[id] = event.target;
        this.setState({ anchorElements });
    }
    handleItemClose = (id, event) => {
        let { anchorElements } = this.state;
        anchorElements[id] = null;
        this.setState({ anchorElements });
    }
    render() {
        let { styles } = this.props;
        const { items, anchorElements } = this.state;
        return (
            <Paper className="main">
                <Table className={styles.table} aria-label="simple table">
                    <TableHead>
                        <TableRow>
                            <TableCell>Item Name</TableCell>
                            <TableCell align="right">Quantity</TableCell>
                            <TableCell align="right">Price</TableCell>
                            <TableCell align="right">Action</TableCell>
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {items.map(row => (
                            <TableRow key={row.id}>
                                <TableCell component="th" scope="row"> {row.name} </TableCell>
                                <TableCell align="right">{row.quantity}</TableCell>
                                <TableCell align="right">{row.price}</TableCell>
                                <TableCell align="right">
                                    <IconButton
                                        aria-label="more"
                                        aria-controls="long-menu"
                                        aria-haspopup="true"
                                        onClick={e => this.handleItemClick(row.id, e)}
                                    >
                                        <MoreVert />
                                    </IconButton>
                                    <Menu
                                        id={row.id}
                                        anchorEl={anchorElements[row.id]}
                                        keepMounted
                                        open={Boolean(this.state.anchorElements[row.id])}
                                        onClose={e => this.handleItemClose(row.id, e)}
                                    >
                                        <MenuItem onClick={e => this.handleItemClose(row.id, e)}> View Details </MenuItem>
                                        <MenuItem onClick={e => this.handleItemClose(row.id, e)}> Assign </MenuItem>
                                    </Menu>
                                </TableCell>
                            </TableRow>
                        ))}
                    </TableBody>
                </Table>
            </Paper>
        )
    }
}

Answer №2

It took some digging, but I discovered that eliminating the CustomTableCell declaration and switching all instances of CustomTableCell to standard TableCells actually solved the issue. 🤔 It's puzzling why this workaround worked, especially since the CustomTableCell code was directly copied from the Demos page.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Deactivating an emitted function from a child component in Angular 4

There is a main component: @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { funcBoo():void{ alert("boo"); //return fal ...

Is the CSS content-visibility property compatible with background images?

Can CSS content-visibility and contain-intrinsic-size also be used with the background-image property, or do they only work with IMG tags? Will either of these properties have any impact on the following code snippet? <span id="image"> #i ...

Discovering all the links present on a webpage using node.js

Currently, I am diving into node.js (webdriver) and encountering some challenges. Despite my efforts to search online for examples of the tasks I need help with, I have come up empty-handed. One example that has me stumped is how to log all links from a pa ...

Instead of capturing the event, React Material UI select captures the reference

I am experiencing an issue with the material select component. I would like to be able to capture the entire object in the onChange() function, but currently, it only captures the selected value. For example, if I select the status 'IN PROGRESS', ...

Enabling block scrolling on a parent element using jscrollpane functionality

Is it possible to set up a jscrollpane so that the parent pane doesn't scroll when the child scroll has reached its bottom? Currently, when the child scrolling reaches the bottom, the parent also scrolls. I would like the parent to only scroll when th ...

Error Encountered While Submitting Email Form

I'm having trouble with my email submission form on my website. I've checked the code and it seems fine, but for some reason, the submissions are not going through successfully. Even when bypassing the JavaScript and directly using the PHP script ...

Use regular expressions to automatically generate HTML attributes in your styling

My ionic/angular app generates a custom tag element with a unique _ngcontent attribute on each refresh, like so: <tag _ngcontent-hgr-c2>...</tag> (1st refresh) <tag _ngcontent-agj-c7>...</tag> (2nd refresh) <tag _ngcontent-cfx-c5 ...

Struggling to align materialUI input or textfield horizontally

import {Input} from 'material-ui'; import Select from 'react-select'; I've been trying different ways to adjust the margins and padding, even wrapping them in divs, but I can't seem to get Material UI textfield or input alig ...

Attempting to retrieve an image from a specified div ID within Android Studio

I find myself at a loss for where to even begin with this issue, so I've been stumbling through it. While I've come across some similar posts, I haven't had any success in making them work. My goal is to utilize the div id to retrieve a spe ...

Tips for managing several material-UI Popovers in React.js:

Within my application, there are several Popover components. I have a good understanding of how to manage the state for one specific Popover component using the following code: class App extends Component { constructor(props) { super(props); ...

CSS query: How to eliminate the extra space at the top of a webpage?

How can I eliminate the gray area visible here: The padding in style.css is currently set to: padding: 0; I have attempted to modify this by changing the following: #page { margin-top: 0; } I have tried variations such as: #page { margin-top: 5px !im ...

step-by-step guide for resolving issues with downloading files in node.js

I've been attempting to download files from my server using node.js with the res.download function from Express, but I keep getting an undefined error. The folder path is D:\program\web\java_script\Node\my_project\ketabk& ...

Tips for preventing click events from interfering with execution in React

On my screen, there is a specific image I am looking to prevent all actions while a process is running. When I trigger the Execute button, it initiates an API call that can take 4-5 minutes to complete. During this time, I need to restrict user interacti ...

Condensing the array after it has been returned

After receiving an array object from the API, I have a specific interest in extracting only the keys to create a new array. Is there a more efficient method of achieving this without resorting to using map and creating a new array? The Original Array [ { ...

Encountering issues with proper function of history.listen within React Router

I am struggling to get my function to work every time React detects a change in the URL. The history.listen method is not triggering (the console.log statement is not showing up). I have read that this issue may be related to using BrowserRouter, but when ...

Discover the combobox element and its value can be easily achieved by using Selenium's find_element_by_xpath method

I am having trouble setting a value in a combobox using selenium. The find_element_by_xpath statement is failing to locate the combobox by class or ng-model. Specifically, I am attempting to change the time period for a stock from one day to one week. Her ...

choose the text following a specific section within the class attribute of an element

In my code, I am trying to extract a number from an input text element using the jQuery method find. The class name of the input text contains a variable number denoted as x, following the substring page-id. Here is the approach I have taken: var id = ui ...

Encountering an issue during npm installation where npm ERR cb() function was not invoked

I've configured a proxy in the npm global settings. However, when I try to install a package, I encounter the following error message. Here are the versions of node and npm I am currently using: npm: 6.13.4 node: v12.16.1 Since I am working behind a ...

React: The error message is saying that it cannot retrieve the 'handler' property because it is either undefined or null

I'm having some trouble with event handlers in my React.js project. Every time I try to create an event handler outside of the render function, I end up with an error. Can anyone help me figure out what I'm doing wrong? class CheckboxHandler ext ...

Tips for transforming a UTF16 document into a UTF8 format using node.js

My dilemma involves an xml file that is encoded in UTF16, and I need to convert it to UTF8 for processing purposes. When I use the following command: iconv -f UTF-16 -t UTF-8 file.xml > converted_file.xml The conversion process goes smoothly with the ...