How to get the value of clicked cell in React Material Table? - reactjs

I am trying to get the corresponding value of cell in React Material UI Table Component.
I was looking for already predefined component api properties but couldn't find anything appropriate.
Working with Material UI DataGrid component, I achieved that, getting the selected row via onSelectionModelChange thanks to this answer.
But in this case, Table doesn't have any checkboxes and I need to retrieve the data by clicking.
Here is the codesandbox link and the example code:
import * as React from "react";
import Table from "#mui/material/Table";
import TableBody from "#mui/material/TableBody";
import TableCell from "#mui/material/TableCell";
import TableContainer from "#mui/material/TableContainer";
import TableHead from "#mui/material/TableHead";
import TableRow from "#mui/material/TableRow";
import Paper from "#mui/material/Paper";
export default function BasicTable({ users }: any) {
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>userId</TableCell>
<TableCell align="right">id</TableCell>
<TableCell align="right">Title</TableCell>
</TableRow>
</TableHead>
<TableBody>
{users &&
users.map((user: any) => (
<TableRow
key={users.id}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell align="right">{user.userId}</TableCell>
<TableCell align="right">{user.id}</TableCell>
<TableCell align="right">{user.title}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
Any help will be appreciated.

You can create an onClick function on the cells that you want this behavior to happen. Assuming that you want this on user.title cells and using console.log as example:
<TableCell align="right" onClick={({target}) => console.log(target.textContent)}>{user.title}</TableCell>

Since you are mapping over your data, you can simply use the desired data from the map:
{users &&
users.map((user: any) => (
<TableRow
key={user.id}
onClick={() => console.log(user.id)} // set desired state here
>
<TableCell align="right">{user.userId}</TableCell>
<TableCell align="right">{user.id}</TableCell>
<TableCell align="right">{user.title}</TableCell>
</TableRow>
))}

Related

How to make TableCell with full Table width with MaterialUI in React?

I got a table, which is looking like this:
import { Typography, Table, TableHead, TableRow, TableCell, TableBody } from '#material-ui/core';
const Example = () => {
return (
<>
<Table>
<TableHead>
<TableRow>
<TableCell align="center"><Typography> 1 </Typography></TableCell>
<TableCell align="center"><Typography> Some </Typography></TableCell>
<TableCell align="center"><Typography> Some</Typography></TableCell>
<TableCell align="center"><Typography> Some </Typography></TableCell>
<TableCell align="center"><Typography> Some </Typography></TableCell>
</TableRow>
</TableHead>
<TableBody>
{
// Here I'm loading some async data
// Meanwhile it's fetching I want to display some loading indicator
}
</TableBody>
</Table>
</>
)
}
And in the TableBody before I display a normal TableRows with data I want to display to users loading indicator that is in the middle of the table. So basically I need one TableCell inside this table that is taking all the columns width, so then I will be able to center my indicator.
How can I achieve that using MaterialUI Components and their API to make my table look like this:
You can expand the cell which you want to include the loading indicator like the following.
Table DOM structure should be considered.
<Table>
<TableHead>
{
!isLoaded
? <TableRow>
<TableCell
colSpan={5} // it seems each line has 5 table cells
align="center"
>
<LoadIndicator />
</TableCell>
: <TableBody>
...
}
Using component props.
<Table component="div">
<TableHead component="div" />
{
!isLoaded
? <LoadIndicator>
: <TableBody component="div">
...
}
...

How to put Link from react router dom inside Material UI table

Like the title says I need to put Link inside the table from Material UI, but i get these two errors <td> cannot appear as a child of <a> <a> cannot appear as a child of <tr>. Now obviously I know what these two error messages mean, but I need to put Link as let's say container around cells, because I need to be able to click anywhere inside the row for redirection to another page.
Here is my code:
<TableRow key={index}>
<Link
to={`/edit/${apiData.id}/${apiData.name}/${apiData.email}`}
>
<TableCell align="left" style={{ paddingLeft: 40 }}>
{apiData.name}
</TableCell>
<TableCell align="left">{apiData.email}</TableCell>
<TableCell align="left">{apiData.status}</TableCell>
<TableCell align="left">{roles}</TableCell>
</Link>
<TableCell align="right" style={{ paddingRight: 40 }}>
<RoleButton onClick={handleRoleChange}>
{roles === "Admin" ? "Set as User" : "Set as Admin"}
</RoleButton>
</TableCell>
</TableRow>
Anyone know how to fix this, if You do I would greatly appreciate that
You can use onClick in TableRow.
function HomeButton() {
let history = useHistory();
function onRowClick(name) {
history.push(`/user/${name}`);
}
return (
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Age</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow onClick={() => onRowClick('tom')}>
<TableCell>Tom</TableCell>
<TableCell>26</TableCell>
</TableRow>
</TableBody>
</Table>
);
}

Material-UI Warning: validateDOMNesting(...): <p> cannot appear as a descendant of <p>

I'm using Material UI and I get this error when I click on Collapse cmp (Material UI) which is inside a table:
validateDOMNesting(...): <p> cannot appear as a descendant of <p>. **
I saw same topic but with Typography which I didn't use.
I have no idea if the problem is the Collapse cmp or the element inside it
Here is the code:
import React from 'react'
import KeyboardArrowDownIcon from '#material-ui/icons/KeyboardArrowDown';
import KeyboardArrowUpIcon from '#material-ui/icons/KeyboardArrowUp';
import TableCell from '#material-ui/core/TableCell';
import TableRow from '#material-ui/core/TableRow';
import IconButton from '#material-ui/core/IconButton';
import Collapse from '#material-ui/core/Collapse';
import Box from '#material-ui/core/Box';
import classes from './post.module.scss'
import Button from '#material-ui/core/Button';
export default function PostRow(props) {
const { row, delatePost, loadProfile, fromProfile } = props;
const [open, setOpen] = React.useState(false);
return (
<React.Fragment>
<TableRow onClick={() => setOpen(!open)} style={{ borderBottom: 'unset', cursor: 'pointer' }}>
<TableCell>
עוד
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell align="right">{row.name}</TableCell>
<TableCell align="right" component="th" scope="row">
{row.businessField}
</TableCell>
<TableCell align="right">{row.followers}</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0, }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box margin={0}>
<div className={classes.about}>
<h4>קצת על העסק</h4>
<p>{row.aboutBusiness}
<h4>דרישות</h4>
<p>{row.requirements}</p>
</p>
{fromProfile &&
<Button variant="contained" color="secondary" style={{marginBottom: '15px'}} onClick={async () => {
await delatePost(row._id)
loadProfile()
}}>מחק פוסט</Button>
}
</div>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
thanks guys i will read the articles :) meanwhile I just removed the P element and its working great.

Customize TableRow with Material UI component

I'm using Material UI table example and trying to customize the rows to have my own component to replace the default row.I want to have some margin between the rows and a shadow (using elevation prop of Paper element). This is what I achieved so far:
import React, { useState } from 'react'
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
const MyPaper = (item) => {
return (
<Paper
elevation={6}>
{item}
</Paper>
);
};
const List = () => {
const items = ['a', 'b'];
return (
<div style={{ maxWidth: "100%" }}>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat (g)</TableCell>
<TableCell align="right">Carbs (g)</TableCell>
<TableCell align="right">Protein (g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map(item => (
<TableRow key={item} component={() => MyPaper(item)}>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
)
}
export default List
but the result is being applied only in the first column. How do I fix this to have my custom row to occupy the entire table space?
Thanks in advance
You can do it easily with withstyles property of Material-UI, you can arrange Paper or other MUI components to give them classes and arrange them in styles variable:
import React, { useState } from 'react'
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import { WithStyles } from '#material-ui/core'
const styles = theme => ({
...theme,
Row: {
margin: 10
}
})
const List = () => {
const items = ['a', 'b'];
const {classes} = this.props
return (
<div style={{ maxWidth: "100%" }}>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat (g)</TableCell>
<TableCell align="right">Carbs (g)</TableCell>
<TableCell align="right">Protein (g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map(item => (
<TableRow key={item} className={classes.Row}>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
<TableCell>{item}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
)
}
export default withStyles(styles)(List)

I am looking for how to draw a vertical line on a table component of material ui

Is there a good way to do it?
I am looking for the way...
However, I can't reach reliable information.
https://material-ui.com/ja/components/tables/
make a div above the material-ui table with a unique className, then in css make following changes
eg:
<div className="uniqueName">
<Material UI Table/> //material ui table here
</div>
in Css
.uniqueName th,
td {
border: 1px solid rgba(224, 224, 224, 1);
}
This is not conventional, but it does the trick. I achieved this by adding Borders around each <TableCell> component. You can also wrap <TableRow> or <TableHead> components. Given below is an example of how to add a Right Border on a cell. If you want the middle verticle line, then add a Right Border on all the <TableCell> of the first column.
const styles = theme => {
tableRightBorder : { borderWidth: 0, borderWidth: 1, borderColor: 'red',borderStyle: 'solid'} // or borderTop: '1px solid red'
}
...
class TableComponent ...
{ classes } = this.props;
<Table >
<TableHead>
<TableRow >
<TableCell className={classes.tableRightBorder}>Column 1</TableCell>
<TableCell>Column 2</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell className={classes.tableRightBorder}>Cell 1</TableCell>
<TableCell>Cell 2</TableCell>
</TableRow>
</TableBody>
</Table>
export default withStyles(styles)(TableComponent)
This will look like this...
For a complete working component of the above image, try this table
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '#material-ui/styles';
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from '#material-ui/core';
import { connect } from 'react-redux';
const useStyles = makeStyles(theme => ({
root: {},
tableRightBorder: {
borderWidth: 0,
borderRightWidth: 1,
borderColor: 'black',
borderStyle: 'solid',
},
}));
const DataTable = props => {
const classes = useStyles();
return (
<Table>
<TableHead>
<TableRow>
<TableCell className={classes.tableRightBorder}>
Column 1
</TableCell>
<TableCell>Column 2</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell className={classes.tableRightBorder}>
Cell 1
</TableCell>
<TableCell>Cell 2</TableCell>
</TableRow>
</TableBody>
</Table>
);
};
DataTable.propTypes = {
className: PropTypes.string,
};
function mapStateToProps() {}
export default connect(mapStateToProps, {})(DataTable);
I like to do it like this; wrap the component with styling and use it as a new component:
const CellWithRightBorder = withStyles((theme: Theme) =>
createStyles({
root: {
borderRightWidth: 1,
borderRightColor: theme.palette.grey[300],
borderRightStyle: "solid",
},
})
)(TableCell);
const MyTable = () => {
<TableContainer component={Paper}>
<Table size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<CellWithRightBorder>Bla</CellWithRightBorder>
</TableRow>
</TableHead>
</Table>
</TableContainer>
}

Resources