Material Table inner onClick shows only last row value - reactjs

So the problem I am having is that I have a custom rendered column inside which there is a menu button clicking on it open a menu like this:
Now look at below code:
columns={[
{
title: 'Actions',
field: 'tableData.id',
render: rowData => {
return (
<div>
<IconButton aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
<MenuIcon />
</IconButton>
<Menu
className={classes.menu}
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem className={classes.sendMail} onClick={()=>
{console.log(rowData)}}>
<ListItemIcon className={classes.icon}>
<SendIcon fontSize="default" />
</ListItemIcon>
Send Assessment Email
</MenuItem>
</Menu>
</div>
)
},
},
The values coming in from the rows i.e rowData is fine on the first onClick of IconButton component but the second onClick of MenuItem shows only the last rowData value no matter which row i select.
Any help would be appreciated. Thank you.
EDIT: I have deployed a quick fix by setting the selected row on Menubutton inside useState and then using that value for the other actions but i wanna know if that is natively or shall i say possible on default rather then the approach i took . i tried stopping event propagation but in vain.

Thanks for asking this questions and seeing that I'm not completely alone...
I am not sure if this could serve as a solution or as a work around, but it works for me.
On the button being used to open the menu, I use the onClick event to set the selected menu row which I want to use, and save it
to the component state.
const [slcRow, setSlcRow] = React.useState(null);
const handleClick = (event, row) => {
setAnchorEl(event.currentTarget);
setSlcRow(row);
};
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={(event ) => {handleClick(event, row) }}
>
Open Menu
</Button>
In the MenuItem onClick event I check the state to retrieve that row and do the work needed...
const handleEditOpen = (event) => {
let row = slcRow;
loadEditData(row.clientId);
setEdit(true);
setAnchorEl(null);
};
<Menu id="long-menu" anchorEl={anchorEl} keepMounted open={open} onClose={handleClose1}>
<MenuItem onClick={(event) => { handleEditOpen(event) }}>Edit </MenuItem>
</Menu

Related

MUI table icon button in a row where row is clickable

The table rows are clickable:
<TableRow
sx={{ '&.MuiTableRow-root': { cursor: 'pointer' } }}
hover
key={row.id}
onClick={() => handleRowClick(row.id)}
>
I have an icon button in one column:
<TableCell>
<Tooltip title='Survey options'>
<IconButton
onClick={() => console.log('button clicked!')}
>
<MoreHoriz />
</IconButton>
</Tooltip>
</TableCell>
The problem is when clicking the icon button it also triggers the onClick of the entire row:
Clicking this:
onClick={() => console.log('button clicked!')}
Also triggers this:
onClick={() => handleRowClick(row.id)}
Is there a way to separate the clicking behavior? I want to be able to click each one separately.
In the IconButton onClick, modify the code like this,
onClick={(event) => {event.stopPropagation(); console.log('button clicked!');}}
The stopPropagation() method prevents propagation of the same event from being called. Propagation means bubbling up to parent elements or capturing down to child elements.

How to get a specific ListItem from Menu Component in MUI for React

I have a List that has several ListItems which I get from an array, let's call it myCollection. Each ListItem has a MenuIcon which opens a Menu, showing an option to delete the item. The simplified code looks like this:
<List>
<Menu
open={Boolean(anchorEl)}
anchorEl={anchorEl}
...>
<MenuItem onClick={() => handleDelete(⚡collectionItem)}>Delete</MenuItem>
</Menu>
{myCollection.map((collectionItem) => (
<ListItem secondaryAction={
<IconButton onClick={(e) => setAnchorEl(e.currentTarget)}>
<MoreVertIcon />
</IconButton>
}>
{collectionItem.name}
</ListItem>
)}
</List>
My problem is that I need to know which item in myCollection was selected to pass it to the delete function. However, I don't have a reference to the current collectionItem in the myCollection array from the Menu. Moving the Menu into the map function makes no sense because multiple menus would be rendered. How can I solve this problem?
I solved it by giving the IconButtons custom HTML data attributes, e.g.
<IconButton data-collection-id={collection.id} onClick={...}>
...
</IconButton>
Then, in the onClick function, we can retrieve it by using event.currentTarget.getAttribute("data-collection-id").

Unable to show Menu item by clicking on the icon using Reactjs

I'm new to framework, I wanted to show menu item when we click on the icon, I couldn't able to figure it out where I'm going wrong.
here is the code:
<div>
<IconButton
aria-label="more"
aria-controls="simple-menu"
aria-haspopup="true"
onClick={this.handleClick}
>
<AccountBalanceIcon />
</IconButton>
<Menu
id="simple-menu"
anchorEl={this.state.anchorEl}
keepMounted
open={Boolean(this.state.anchorEl)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>My account</MenuItem>
<MenuItem onClick={this.handleClose}>Logout</MenuItem>
</Menu>
</div>
Can anyone help me in getting a popup while I click on the icon
The IconButton does not have a value, so you're setting state to undefined. You just want the target anyway, since its the element itself that will serve as the anchor, not the value.
Change your handler to this:
handleClick = event => {
this.setState({ anchorEl: event.target });
};
Also: Please provide all the relevant code the the question itself. The event handlers are the most important part of the problem and they are only located off-site.

How to show only icon to the particular user when we click on it using reactjs

I'm trying to show icon when it is hovered and clicked on the particular User but here when i click on the icon of particular user then i could see for the other users also showing the icon without hovering or clicking on it. Can anyone help me in this query?
Here is code:
<Card>
{Data.map(user => (
<CardHeader
key={user.id}
className={classes.header}
avatar={<Avatar aria-label="recipe">R</Avatar>}
action={
<div className={this.state.menu && classes.menu}>
<IconButton
id="simple-menu"
className={classes.showIcon}
aria-label="settings"
aria-controls="simple-menu"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
style={{ marginTop: "35px" }}
id="simple-menu"
keepMounted
anchorEl={this.state.menu}
open={Boolean(this.state.menu)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>View</MenuItem>
<MenuItem onClick={this.handleClose}>hide</MenuItem>
</Menu>
</div>
}
title={user.title}
subheader={user.subheader}
/>
))}
</Card>
https://codesandbox.io/s/material-ui-menu-button-visibility-fix-hujx4
For ex: if i click on Shrimp and Chorizo Paella User (dot icon) then we could see same icon visible in the other user Sherlock holmes. My objective is to show the icon whenever i hover the user card, and when we click on the icon, then the icon should visible only on the respective user card but not in other User card
The problem is you are using the same state for all of your cards. You are deciding on
the basis of state.menu for all cards resulting in the same behaviour no matter on which card the event has occured. As a result if the state.menu is set to value by hovering on any card & the menu of all the cards is visible. To solve this you will need to uniquely identify your card. For that you will need to manage state for each card. You can achieve it like this:
Create a state for each card identified by user.id using the componentDidMount lifecycle hook before return the <Card> component.
let cardStates = {}
Data.map(user => {
cardStates[user.id] = { menu: null }
});
this.setState(cardStates);
...
Convert your handle events to callbacks
<Menu
style={{ marginTop: "35px" }}
id="simple-menu"
keepMounted
anchorEl={this.state[user.id].menu}
open={Boolean(this.state[user.id].menu)}
onClose={this.handleClose}
>
<MenuItem
onClick={e => {
this.handleClose(e, user.id);
}}
>
View
</MenuItem>
<MenuItem
onClick={() => {
this.handleClose(user.id);
}}
>
hide
</MenuItem>
</Menu>
Manipulate state in handlers by accepting your user.id as argument.
handleClick = (e, uid) => {
let newCardState = {}
newCardState[uid] = { menu: e.target }
this.setState(newCardState);
};
handleClose = (uid) => {
let newCardState = {}
newCardState[uid] = { menu: null}
this.setState(newCardState);
};

Is there a way to use <Collapse> as my Transition component while using the <Popper> component to display a Menu onHover?

The following question is regarding React and Material-UI:
I am trying to use the <Collapse> transition component when displaying my <Menu> onMouseEnter. However, there seems to be an issue in the Material-UI library when it comes to the way the <Collapse> component and the <Popper> / <Popover> component. The issue is currently open and can be seen here.
Has anyone found a good workaround for this? Basically, I am just hoping to have a subnav Menu appear when you hover over a link with this specific transition.
I have tried using the <Grow> component and the transition works just fine, but we specifically are trying to use the <Collapse> transition.
export const NavBarItem = ({ navItem }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
function handleToggle() {
setOpen(prevOpen => !prevOpen);
}
function handleClose(event) {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
}
return (
<React.Fragment>
<Link className={classes.link} href={BASE_HOMEPAGE + navItem.path}>
<Typography
className={classes.title}
ref={anchorRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
>
{navItem.title}
</Typography>
</Link>
<Popper
open={open}
anchorEl={anchorRef.current}
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
transition
disablePortal
placement="bottom-start"
>
<Collapse in={open}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={handleClose}>
<MenuList className={classes.paperMenu}>
{navItem.menuItems.map(item => (
<Link
className={classes.link}
href={
item.external ? item.path : BASE_HOMEPAGE + item.path
}
>
<MenuItem
className={classes.paperMenuItem}
onClick={handleClose}
>
{item.text}
</MenuItem>
</Link>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Collapse>
</Popper>
</React.Fragment>
);
};
The code shown above is for a specific NavItem in a NavComponent. It is essentially just a dropdown component to show a subnav when you hover over a specific link.
Thank you for your help and please let me know if you need anymore additional information.
You can try to use the TransitionProps given by the Popper when using the transition props, as shown in the documentation
<Popper id={id} open={open} anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<div className={classes.paper}>The content of the Popper.</div>
</Fade>
)}
</Popper>
For smoother UI you can also use the keepMounted property in Popper:
<Popper id={id} open={open} anchorEl={anchorEl} transition keepMounted>

Resources