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

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>
);
}

Related

How to add a column link to material-ui table and redirect to summary detail page using column link id

I am working Material-UI tables, such as the following basic table here but I have added an id column at the beginning.
Assuming I have this basic table example at the route localhost:3000/basic-table within my React app, how can I take the below code and make the <tableCell>{row.id}</tableCell> into a <a href link> which will allow the user to click on this {row.id} column and then present the user with a new screen, where I can take this id and show more data about it?
I will also need a means of returning back to the main page report, i.e. parent page.
What I am trying to achieve is basically from the main parent report, a user can click on a row id, which would then present the user with a detailed report based on that id, i.e. like a drill-down report.
From the doco, I can't find any examples where I can achieve this as unsure how to add a column link.
Can anyone help with this or point me to an example.
{rows.map((row) => (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.id}
</TableCell>
<TableCell align="right">{row.name}</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</TableCell>
</TableRow>
))}
You can use history API
import { useHistory } from 'react-router-dom';
const YourComponent = () => {
...
const history = useHistory();
return {
...
rows.map((row) => (
<TableRow key={row.id} onClick={() => history.push(yourLocation)}>
<TableCell component="th" scope="row">
{row.id}
</TableCell>
<TableCell align="right">{row.name}</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</TableCell>
</TableRow>
))}
}

Material UI, Warning <td> cannot appear as a child of <div>

I'm using React, typescript and Material UI. I've created a pretty common "Create user form" with basic inputs for username, name, email, ect. Added two buttons, "Edit" and "Delete." Everything seems to function properly, however, I cannot get this error message resolved.
Warning: validateDOMNesting(...): <td> cannot appear as a child of <div>.
Here's the table from a react component:
<TableContainer className={classes.scroll} component={Paper}>
<Table stickyHeader aria-label="table">
<TableHead>
<TableRow>
<TableCell>Username</TableCell>
<TableCell align="right">First name</TableCell>
<TableCell align="right">Last name</TableCell>
<TableCell align="right">Email</TableCell>
<TableCell align="right">Connect_username</TableCell>
<TableCell align="right">Role</TableCell>
<TableCell align="left">Edit</TableCell>
<TableCell align="left">Delete</TableCell>
</TableRow>
</TableHead>
<TableBody>
{(rowsPerPage > 0
? props?.items.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
: props?.items
).map(item => (
<TableRow key={item.user_id}>
<TableCell component="th">{item.username}</TableCell>
<TableCell align="right">{item.first_name}</TableCell>
<TableCell align="right">{item.last_name}</TableCell>
<TableCell align="right">{item.email}</TableCell>
<TableCell align="right">{item.connect_username}</TableCell>
<TableCell align="right">{item.role?.map(r=>r.role).join(",")}</TableCell>
<TableCell>
<Button onClick={() => props.handleEdit(item)}>Edit</Button>
</TableCell>
<TableCell>
<Button onClick={() => props.handleConfirmDelete(item.user_id)}>Delete</Button>
</TableCell>
</TableRow>
))}
</TableBody>
<TablePagination
rowsPerPageOptions={[10, 25, { label: 'All', value: -1 }]}
count={props.items.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Table>
</TableContainer>
component={Paper} is likely causing this. Can you try removing it? If you want the table to appear on a Paper component, then try nesting TableContainer under Paper.
put TablePagination in the TableBody tag and wrap it in TableRow.
Had a similar issue and this fixed it.
Like this:
<TableBody>
{(rowsPerPage > 0
? props?.items.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
: props?.items)
.map(item => (
<TableRow key={item.user_id}>
<TableCell component="th">{item.username}</TableCell>
<TableCell align="right">{item.first_name}</TableCell>
<TableCell align="right">{item.last_name}</TableCell>
<TableCell align="right">{item.email}</TableCell>
<TableCell align="right">{item.connect_username}</TableCell>
<TableCell align="right">{item.role?.map(r=>r.role).join(",")}</TableCell>
<TableCell>
<Button onClick={() => props.handleEdit(item)}>
Edit
</Button>
</TableCell>
<TableCell>
<Button onClick={() => props.handleConfirmDelete(item.user_id)}>
Delete
</Button>
</TableCell>
</TableRow>
<TableRow>
<TablePagination
rowsPerPageOptions={[10, 25, { label: 'All', value: -1 }]}
count={props.items.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</TableRow>
))}
</TableBody>
update: "#mui/material": "^5.10.9"
in my case this error was causing TablePagination and not Paper component.
working solution is wrapping pagination not only with row but also footer as follow
<TableContainer component={Paper}>
<Table>
<TableBody>
...
</TableBody>
<TableFooter>
<TableRow>
<TablePagination />
</TableRow>
</TableFooter>
</Table>
</TableContainer>
mui docs: https://mui.com/material-ui/react-table/#custom-pagination-actions

Material Table - nested columns

Is it possible to make a table with nested columns using material-table library?
Final result that I want to achieve
Yes its possible with material-table . You have to use Components property to achieve that.
function App() {
const columns = [...];
const data = [...];
return (
<div className="App">
<MaterialTable
columns={columns}
data={data}
components={{
Header: props => {
return (
<TableHead>
<TableRow>
<TableCell colSpan={2} align="center">
Average A
</TableCell>
<TableCell colSpan={2} align="center">
Average B
</TableCell>
</TableRow>
<TableRow>
<TableCell align="center">Lower</TableCell>
<TableCell align="center">Upper</TableCell>
<TableCell align="center">Lower</TableCell>
<TableCell align="center">Upper</TableCell>
</TableRow>
</TableHead>
);
},
Row: ({ data }) => {
return (
<TableRow>
<TableCell align="center">{data.lowerA}</TableCell>
<TableCell align="center">{data.upperA}</TableCell>
<TableCell align="center">{data.lowerB}</TableCell>
<TableCell align="center">{data.upperB}</TableCell>
</TableRow>
);
}
}}
/>
</div>
);
}
DEMO: Codesandbox link
You can use colspan. Check example here.
https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_td_colspan

React - how to wrap a table row with Link

I have a table that I built using react mui. In that table I have a row, that looks like this:
<TableRow
hover
onClick={() => onRowClicked(item)}
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={item.id}
data-testid={item.id}
selected={isSelected}
className={classes.tr}
>
<TableCell padding="checkbox" classes={{body: classes.smWidth}} onClick={(event) => onCheckboxClick(event, item.id)}>
<Checkbox checked={isSelected}/>
</TableCell>
<TableCell component="th" scope="row" classes={{body: classes.id}}>{item.id}</TableCell>
<TableCell align="left">{item.text}</TableCell>
<TableCell align="left">{item.code}</TableCell>
<TableCell align="left">{item.type}</TableCell>
<TableCell align="left"><StatusLabel status={item.substatus || item.status} size="large"/></TableCell>
<TableCell align="left">{getElapsedTime(new Date(item.updated), now)}</TableCell>
</TableRow>
And this works fine, but instead of using onClick function to navigate to each item, I would like to use link, so that I also get on control/cmd click possibility to open link in a new tab. I have tried just by wrapping the whole TableRow with Link component:
<Link to={`/${item.id}`}>
<TableRow
hover
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={item.id}
data-testid={item.id}
selected={isSelected}
className={classes.tr}
>
<TableCell padding="checkbox" classes={{body: classes.smWidth}} onClick={(event) => onCheckboxClick(event, item.id)}>
<Checkbox checked={isSelected}/>
</TableCell>
<TableCell component="th" scope="row" classes={{body: classes.id}}>{item.id}</TableCell>
<TableCell align="left">{item.text}</TableCell>
<TableCell align="left">{item.code}</TableCell>
<TableCell align="left">{item.type}</TableCell>
<TableCell align="left"><StatusLabel status={item.substatus || item.status} size="large"/></TableCell>
<TableCell align="left">{getElapsedTime(new Date(item.updated), now)}</TableCell>
</TableRow>
</link>
But, then the whole table styling is out of place. What is the right way to do this then?

How do I make this table sortable?

I think this is an easy problem, but I am struggling to understand how to do this since I don't have a class. I am trying to make this table sortable. I want to be able to sort based on the column that is clicked on.
Do I need to add a class? I am very new to ReactJS. Thanks for your help!
function CreateGradeTable(props) {
return (
<div>
<Table>
<TableHead>
<TableRow>
<TableCell className={props.tHead}>Student</TableCell>
<TableCell className={props.tHead}>Course</TableCell>
<TableCell className={props.tHead}>Term</TableCell>
<TableCell className={props.tHead}>Grade</TableCell>
<TableCell className={props.tHead}>Final</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.data.map((gradeDetail, i) => {
const {
gradeId,
courseName,
courseId,
studentName,
studentId,
courseTerm,
grade,
finalGradeForTerm,
} = gradeDetail;
return (
<TableRow
key={gradeId}
className={`${props.tRow} ${i % 2 !== 0 ? props.striped : ''}`}
>
<TableCell>
<Link to={`/student/${studentId}`}>
<StyledLink>{studentName}</StyledLink>
</Link>
</TableCell>
<TableCell>
<Link to={`/course/${courseId}`}>
<StyledLink>{courseName}</StyledLink>
</Link>
</TableCell>
<TableCell align="left">{courseTerm}</TableCell>
<TableCell align="left">{grade}</TableCell>
<TableCell align="left">{finalGradeForTerm}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
}
I see that you are using Material-UI to display the table.
You need to use 'TableSortLabel' to display Header. This will also show ascending/descending arrows.
Then write an onClick handler on TableSortLabel to change state thus triggering re-render.
See the working example here
https://codesandbox.io/s/condescending-beaver-q0owe?fontsize=14
<TableBody>
{
props.data.sort(order === 'asc'? ascCompare: desCompare ).map((gradeDetail, i) => {
const {
grade,
courseName,
studentName,
} = gradeDetail;
return (
<TableRow
key={i}
>
<TableCell align="left">{grade}</TableCell>
<TableCell align="left">{studentName}</TableCell>
<TableCell align="left">{courseName}</TableCell>
</TableRow>
);
})}
</TableBody>

Resources