So basically I have this table that needs to have an action menu button. When it renders, it copies the last ID of the given array. I don't know what's the problem behind this mess actually. I've tried out various solutions and they did not tend to answer my problem.
Here's my actual code.
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TablePagination,
TableRow,
TableSortLabel,
Paper,
Button,
Menu,
MenuItem
} from '@material-ui/core';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp';
import { useStyles } from './table-started.styles';
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
return 1;
}
return 0;
}
function getComparator(order, orderBy) {
return order === 'desc'
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
}
function stableSort(array, comparator) {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const order = comparator(a[0], b[0]);
if (order !== 0) return order;
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
}
const headCells = [
{ id: 'title', disablePadding: false, label: 'Title' },
{ id: 'author_name', disablePadding: false, label: 'Author(s)' },
{ id: 'created_at', disablePadding: false, label: 'Started' },
{ id: 'actions', disablePadding: false, label: 'Actions' }
];
function EnhancedTableHead(props) {
const tableStyles = useStyles();
const { classes, order, orderBy, onRequestSort } = props;
const createSortHandler = (property) => (event) => {
onRequestSort(event, property);
};
return (
<TableHead className={tableStyles.tableContainer}>
<TableRow>
{headCells.map((headCell) => (
<TableCell
key={headCell.id}
className={tableStyles.tableTitle}
align='left'
padding='default'
sortDirection={orderBy === headCell.id ? order : false}
>
<TableSortLabel
className={tableStyles.tableTitle}
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : 'asc'}
onClick={createSortHandler(headCell.id)}
>
{headCell.label}
{orderBy === headCell.id ? (
<span className={classes.visuallyHidden}>
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
</span>
) : null}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
);
}
EnhancedTableHead.propTypes = {
classes: PropTypes.object.isRequired,
numSelected: PropTypes.number.isRequired,
onRequestSort: PropTypes.func.isRequired,
onSelectAllClick: PropTypes.func.isRequired,
order: PropTypes.oneOf(['asc', 'desc']).isRequired,
orderBy: PropTypes.string.isRequired,
rowCount: PropTypes.number.isRequired
};
const TableStarted = ({ ctrResults }) => {
const classes = useStyles();
const [order, setOrder] = useState('asc');
const [orderBy, setOrderBy] = useState('calories');
const [selected, setSelected] = useState([]);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [rows, setRows] = useState([]);
useEffect(() => {
if (ctrResults) {
console.log(ctrResults);
setRows(ctrResults);
}
}, [ctrResults]);
const handleRequestSort = (event, property) => {
const isAsc = orderBy === property && order === 'asc';
setOrder(isAsc ? 'desc' : 'asc');
setOrderBy(property);
};
const handleSelectAllClick = (event) => {
if (event.target.checked) {
const newSelecteds = rows.map((n) => n.name);
setSelected(newSelecteds);
return;
}
setSelected([]);
};
const handleClick = (event, name) => {
const selectedIndex = selected.indexOf(name);
let newSelected = [];
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, name);
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1));
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1));
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(
selected.slice(0, selectedIndex),
selected.slice(selectedIndex + 1)
);
}
setSelected(newSelected);
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
const isSelected = (name) => selected.indexOf(name) !== -1;
const emptyRows =
rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage);
const [anchorEl, setAnchorEl] = React.useState(null);
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const goToEdit = (id, e) => {
e.preventDefault();
window.location.href = `/submission/results/${id}`;
};
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<TableContainer>
<Table
className={classes.table}
aria-labelledby='tableTitle'
size='medium'
aria-label='enhanced table'
>
<EnhancedTableHead
classes={classes}
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={rows.length}
/>
<TableBody className={classes.tableBody}>
{stableSort(rows, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
const isItemSelected = isSelected(row._id.$oid);
const labelId = `enhanced-table-checkbox-${index}`;
let author_name = row.author_first_name
? row.author_first_name
: '';
author_name = row.author_last_name
? author_name + ' ' + row.author_last_name
: 'N/A';
return (
<TableRow className={classes.tableRow}>
<TableCell
className={classes.tableData}
padding='default'
component='th'
id={labelId}
scope='row'
>
{row.title}
</TableCell>
<TableCell
scope='row'
className={classes.tableData}
align='left'
>
{author_name}
</TableCell>
<TableCell
scope='row'
className={classes.tableData}
align='left'
>
{row.created_at.substring(0, 10)}
</TableCell>
<TableCell
scope='row'
className={classes.tableData}
align='left'
>
<Menu
id='actions'
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={(e) => goToEdit(row._id.$oid, e)}>
Edit
</MenuItem>
<MenuItem onClick={handleClose}>Delete</MenuItem>
</Menu>
<Button
aria-controls='simple-menu'
aria-haspopup='true'
onClick={handleMenuClick}
className={classes.menuButton}
endIcon={
anchorEl ? (
<ArrowDropUpIcon />
) : (
<ArrowDropDownIcon />
)
}
>
Actions
</Button>
</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 20]}
component='div'
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Paper>
</div>
);
};
export default TableStarted;
and here's the sample Menu:
Menu Sample
but it gets the last rows array's row._id.$oid in each row. How can I get each unique's ID?
When I do console.log, the row._id.$oid is being replaced.
Row ID Console.log
It seems that each row is sharing the same menu items. You can validate this if you add a new item that will display the current row id. This might be because you are reusing anchorEl.
...
<MenuItem onClick={(e) => goToEdit(row._id.$oid, e)}>Edit</MenuItem>
<MenuItem onClick={handleClose}>Delete</MenuItem>
<MenuItem>{row._id.$oid}</MenuItem> // this will display the last row's id
A possible solution would be to create a separate component for your row menu items.
// RowMenu.js
...
export function RowMenu({ row, goToEdit }) {
const [anchorEl, setAnchorEl] = React.useState(null);
const classes = useStyles();
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<Menu
id={`actions-${row._id.$oid}`}
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={(e) => goToEdit(row._id.$oid, e)}>Edit</MenuItem>
<MenuItem onClick={handleClose}>Delete</MenuItem>
<MenuItem>{row._id.$oid}</MenuItem>
</Menu>
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleMenuClick}
className={classes.menuButton}
endIcon={anchorEl ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />}
>
Actions
</Button>
</>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With