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

Load styles in Nuxt asynchronously to improve performance

Is there a way to load styles asynchronously on the website or insert them in the footer? I am currently using Nuxt version 2.0.0 Here's what I have tried so far: Adding a plugin in webpack called async-stylesheet-webpack-plugin. However, this res ...

I am having trouble viewing elements located below a div that I created using CSS

Currently, I am working on creating a portfolio page where the initial page opens with a height of '100vh' and width of '100%', which seems to be functioning correctly. However, I am facing an issue where I am unable to scroll down to v ...

Utilize Hardhat and NPM to distinguish between unit tests and integration tests efficiently

Struggling with setting up two commands in my package.json for running unit tests and integration tests. I am having trouble defining the location of the testset for each type of testing. Within the scripts section of my package.json, I have created two c ...

The absence of data in a c# web api controller is causing issues with jQuery AJAX post requests

When I am sending data to a c# web api controller, I use the following method: $.ajax({ type: "POST", url: "menuApi/menu/Cost", data: JSON.stringify(order), contentType: "application/json", success: function (data) { window.alert(&apo ...

Unable to transmit information back to React

Recently stepping into the world of React and Node.js, I have successfully created a function in my Node.js application that executes a Python script using child process. However, I seem to be facing a challenge with my router post method named pythonExecu ...

Using $nin alongside $and in Mongoose

Implementing a filter for an admin user using mongoose operations. The user should be able to view all saved files except for those that are classified as draft files. However, the admin user should still have access to their own saved draft files. Code ...

Prevent overflow of content and ensure text does not automatically resize when expanding

Apologies for the lengthy post, although it appears long because of the images. I aim to achieve a layout similar to this: https://i.stack.imgur.com/kuX6Tm.png To create this layout, I used the following code snippet: <?xml version="1.0" encoding="u ...

trouble encountered while sending data to php using ajax and json

Despite trying multiple solutions, my script is still not working properly. It functions without the $_POST value and without JSON, but when both are included, it fails to work. The error message displayed by the function is as follows: <b>Notice< ...

Tips for personalizing the weekday title of Material-UI's DateRangePicker

I've been struggling for hours trying to customize the weekday titles in Material-ui DateRangePicker. Instead of displaying "S", "M",..., I want to show the titles as I desire. I attempted to customize the dateAdapter without succe ...

Encountered an error while trying to create module kendo.directives using JSPM

I am attempting to integrate Kendo UI with Angular in order to utilize its pre-built UI widget directives. After running the command jspm install kendo-ui, I have successfully installed the package. In one of my files, I am importing jQuery, Angular, and ...

Defining the flow and functionality

I'm currently attempting to define a function signature using Flow. I had anticipated that the code below would generate an error, but surprisingly, no errors are being thrown. What could be causing this issue? // This function applies another functi ...

What causes React JS to continuously render in an infinite loop when using hooks and useState

I am struggling with updating the current state of my component based on a result using a custom hook in React. Whenever I try to update it, I end up in an infinite loop rendering due to my usage of the useState() hook. I am still new to working with Rea ...

Preventing Users from Selecting Past Dates in Material-UI datetime-local TextField

I am striving to prevent selection of past dates but have not been successful so far. Below is the code snippet: <TextField variant="outlined" id="datetime-local" label="Select Date and Time" placeholder="Sele ...

Integrate the retrieved information into a new object and then proceed to export it

Hey there! I'm looking to retrieve data from an API and merge it with some existing data in an array of objects. The goal is to then export this combined data for use in another part of my web application. Check out the following code example: //expo ...

Hiding the overflow conceals the entire image in one direction, while leaving the other exposed

Here is the code I have written for my project (view fiddle here): img { width: 200px; height: 200px; } .image-container { width: 600px; height: 200px; overflow: hidden; } I am working with multiple images, all sized at 200px by 200p ...

What steps do I need to take to translate jQuery code into standard JavaScript code?

Can someone please help me convert this jQuery code to plain JavaScript? window.addEventListener('scroll', function() { document.querySelectorAll('.container p').forEach(function(el) { var scrollTop = window.scrollY, ...

Leveraging the "dialogclose" event within jQuery Mobile

Is there a way to change an image once it is clicked and change back when the dialog it links to is closed? I found a potential solution on this site, but after modifying it for my needs, it doesn't seem to work. Can anyone help me figure out what I a ...

json success function not being triggered

I am facing an issue with executing the success function in my code while trying to post the value of an input box and retrieve the value of a checked radio button. The objective is to perform a query based on which radio button is checked. Here is the HT ...

CSS: Creating a block that stretches the entire width of its parent block

I've been facing the same issue multiple times. Whenever I use the float property to display one block, the next block ends up overlapping with the first one. For example: Consider the following block of code: .row_item{ width: 30%; display: block; ...

Having trouble with the "Corrupted @import" error during grunt build?

As I embark on my journey to create my very first Angular application, I have encountered a roadblock. Using Yeoman and angular-generator, everything seemed to be running smoothly with "grunt serve." However, when I attempted to execute "grunt build," the ...