I have an app running at this URL:
https://sentify-kth.herokuapp.com/my-searches
As you can see, there is a circular loading animation in the table. I want to place this animation in the middle of the table body, like this (imagine that it's in the center and not slightly to the right):
I can't get this to work. My attempt has been to style the element with class=progress. I've tried width:100%; margin:auto. I've also tried text-align:center. That didn't work either. I don't know what else to try.
How can I center the circular animation?
The React code:
render() {
const { classes } = this.props;
const { data, selected, rowsPerPage, page } = this.state;
let tableBody;
let emptyRows;
switch(this.state.status){
case "LOADING":
tableBody = <CircularIndeterminate/>;
emptyRows = undefined;
break;
case "LOADED":
tableBody = <CircularIndeterminate/>;
break;
}
return (
<Paper className={classes.root}>
<EnhancedTableToolbar
numSelected={selected.length}
handleClickDeleteBtn={this.handleClickDeleteBtn}
open={this.state.open}
handleCloseModal={this.handleCloseModal}
handleConfirm={this.handleConfirm}
handleCancel={this.handleCancel}
/>
<div className={classes.tableWrapper}>
<Table className={classes.table}>
<EnhancedTableHead
numSelected={selected.length}
onSelectAllClick={this.handleSelectAllClick}
rowCount={data === null || data === undefined ? -1 : (data.length || -1)}
/>
<TableBody>
{tableBody}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</div>
<TablePagination
component="div"
count={data === null || data === undefined ? 0 : data.length || 0}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'Previous Page',
}}
nextIconButtonProps={{
'aria-label': 'Next Page',
}}
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
/>
</Paper>
);
}
}
CircularIndeterminate.js:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import { CircularProgress } from 'material-ui/Progress';
const styles = theme => ({
progress: {
margin: theme.spacing.unit * 2,
},
});
function CircularIndeterminate(props) {
const { classes } = props;
return (
<div className="progress">
<CircularProgress className={classes.progress} size={100} thickness={4}/>
</div>
);
}
CircularIndeterminate.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(CircularIndeterminate);
Here's how I solved it (there was an answer saying pretty much the same thing, but it was removed for an unknown reason):
Put the circle in a tr and td element
Set colspan=6 on the td element
Set text-align:center for the .progress element.
Code:
tableBody = (
<tr>
<td colspan="6">
<CircularIndeterminate/>
</td>
</tr>
);
css:
.progress{
text-align:center
}
Related
I'm trying to use arrays in Grommet DataTable. My data looks like this :
{
customer: [
'BANANA',
'Banana',
'banana',
'republic of banana'
],
somethingelse: ['ABC','123','DEF']
}
In a regular Grommet Table , I'm able to use every cell by defining the first value from the array as title - for example customer[0] - and create an expandable arrow to show the rest of the data in 'customer' :
But I don't get how to do this on a cell basis for a Grommet DataTable ?
Here is the way I'm using it in the regular Grommet Table :
<TableCell scope="row" pad={{ left: '2px', righ: '3px' }}>
<TextInput name="tags" size="xsmall" />
</TableCell>
</TableRow>
{searchResults.length > 0 &&
searchResults.map((searchResult, index) => (
<TableRow key={index}>
<TableCell>
<Box direction="row">
<Text size="xsmall">{searchResult.customer[0]}</Text>
{searchResult.customer.length > 1 && (
<Button
plain
hoverIndicator={false}
icon={
isExpanded[index] ? (
<FormDown size="18px" />
) : (
<FormNext size="18px" />
)
}
onClick={() => toggleOpen(index)}
/>
)}
</Box>
<Box>
{isExpanded[index] && listElements(searchResult.customer)}
</Box>
</TableCell>
Here is my Form , using DataTable :
return (
<Form value={formData} onSubmit={onSubmit} onChange={onChange}>
...
<DataTable
fill
border={{ body: 'bottom' }}
paginate
columns={columns}
data={searchResults}
select={select}
onClickRow={(e) => console.log(e.datum)}
onSelect={() => {}}
step={8}
rowDetails={(row) => { // I'm able to use rowDetails to expand and display some data , but how can I use this to 1. Use the [0] element of the array as title and 2. apply to all cells in the row/table.
for (const cell in row) {
// if (cell.length > 1) {
// return listElements(cell);
// }
console.log(cell);
}
}}
...
/>
...
</Form>
);
I was able to achieve that by using the render function and passing a CellElement to it, in which I have created my rules :
const columns = [
{
property: 'customer',
header: <FormField label="Customer" name="customer" size="xsmall" />,
render: (datum) => <CellElement val={datum.customer} />,
},
CellElement.js
import { Box, Text, Button } from 'grommet';
import { FormNext, FormDown } from 'grommet-icons';
import React, { useState } from 'react';
const CellElement = ({ val }) => {
const title = Array.isArray(val) ? val[0] : val;
const [isExpanded, setIsExpanded] = useState({});
const toggleOpen = (category) => {
setIsExpanded({
...isExpanded,
[category]: !isExpanded[category],
});
};
const listElements = (arr) => {
return arr.slice(1).map((el, index) => (
<Text key={index} size="xsmall">
{el}
</Text>
));
};
return (
<Box>
<Box direction="row">
<Text size="xsmall">{title}</Text>
{Array.isArray(val) && val.length > 1 && (
<Button
plain
hoverIndicator={false}
icon={
isExpanded[title] ? (
<FormDown size="18px" />
) : (
<FormNext size="18px" />
)
}
onClick={() => toggleOpen(title)}
/>
)}
</Box>
<Box>{isExpanded[title] && listElements(val)}</Box>
</Box>
);
};
export default CellElement;
I have created a Table with React and MUI, and tried to implement a sorting function for each column in ascending and descending way.
But when I click on the header to sort the column, I get an error, that says "Data is not iterable" in the console, and I have not been able to figure out where the mistake is.
import React, {useEffect, useState} 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';
import TableSortLabel from "#mui/material/TableSortLabel";
import TablePagination from '#mui/material/TablePagination';
import { createStyles, TextField } from '#mui/material';
import "./table.css";
function createUserData (fullname, email, nationality, city){
return {fullname, email, nationality, city};
}
const rows= [];
export default function RandomUserTable(){
const [data, setData]= useState([]);
// const [rowData, setRowData]= useState(rows);
// const [orderDirection, setOrderDirection]= useState("asc");
const [order, setOrder]=useState('asc');
const [searchTerm, setSearchTerm]= useState('');
const [page, setPage] =useState(0);
const [rowsPerPage, setRowsPerPage] =useState(10);
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(+event.target.value);
setPage(0);
};
useEffect(()=>{
fetch('https://randomuser.me/api/?results=30')
.then((response) => {
return response.json();
})
.then((data) => {
setData(data);
console.log(data);
});
}, []);
const sorting=(col)=>{
if(order==='asc'){
const sorted= [...data].sort((a,b)=>
a[col].toLowerCase()>b[col].toLowerCase()?1:-1
);
setData(sorted);
setOrder('dsc')
}
if(order==='dsc'){
const sorted= [...data].sort((a,b)=>
a[col].toLowerCase()<b[col].toLowerCase()?1:-1
);
setData(sorted);
setOrder('asc')
}
}
// const sortArray= (arr, orderBy)=> {
// switch (orderBy){
// case "asc":
// return [...arr].sort ((a,b)=>
// a.city> b.city? 1:b.city > a.city? -1:0
// );
// case "desc":
// return [...arr].sort((a, b)=>
// a.city < b.city ? 1 : b.city< a.city ? -1 : 0
// );
// }
// };
// const handleSortRequest = ()=>{
// setRowData(sortArray(rows, orderDirection));
// setOrderDirection(orderDirection === "asc"? "desc":"asc");
// }
return (
<>
<TextField sx={{ width: 660, marginBottom: "2rem", marginTop: "2rem", border: "2px solid violet" }} className="text-field" onChange={event=>{setSearchTerm(event.target.value)}} placeholder="Search..."></TextField>
<TableContainer component={Paper} sx={{width:800, margin: "0 auto"}}>
<Table stickyHeader className="table" aria-label="simple table">
<TableHead>
<TableRow sx={{'& .MuiTableCell-root':{backgroundColor:"rgb(120, 169, 233)", border: "1px solid white", color: 'white'}}}>
<TableCell align="center">Fullname</TableCell>
<TableCell onClick={()=>sorting("email")} align="center">E-Mail</TableCell>
<TableCell onClick={()=>sorting("nat")} align="center">Nationality</TableCell>
{/* <TableCell align="center" onClick={handleSortRequest}> */}
<TableCell align="center">
<TableSortLabel style={{color: 'white'}} active={true}>City</TableSortLabel>
{/* <TableSortLabel style={{color: 'white'}} active={true} direction={orderDirection}>City</TableSortLabel> */}
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.results?.slice(page*rowsPerPage, page*rowsPerPage+rowsPerPage).filter((val)=>{
if(searchTerm=== ""){
return val
}else if(val.nat.toLowerCase().includes(searchTerm.toLowerCase()) ){
return val
}else if(val.email.toLowerCase().includes(searchTerm.toLowerCase())){
return val
}else if(val.location.city.toLowerCase().includes(searchTerm.toLowerCase())){
return val
}
}).map((user,index) => (
<TableRow key={index} sx={{'& .MuiTableCell-root':{backgroundColor: 'rgba(54, 96, 129, 0.241)', height: '3rem'}}}>
<TableCell align="center" component="th" scope="row">
{ (user.name.first)+ " " +(user.name.last)}
</TableCell>
<TableCell align="center">{user.email}</TableCell>
<TableCell align="center">{user.nat}</TableCell>
<TableCell align="center">{user.location.city}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[10, 25, 100]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</>
);
}
enter image description here
you cant spread object in the array like this
let data= {info:0,result:[1,2,3]}
let spread = [...data]
that's why you get an error "Data is not iterable"
do this instead
const sorting=(col)=>{
if(order==='asc'){
const sorted= {...data,["results"]:data.results.sort((a,b)=>
a[col].toLowerCase()>b[col].toLowerCase()?1:-1
)}
setData(sorted);
setOrder('dsc')
}
if(order==='dsc'){
const sorted= {...data,["result"]: data.results.sort((a,b)=>
a[col].toLowerCase()<b[col].toLowerCase()?1:-1
)}
setData(sorted);
setOrder('asc')
}
}
Okay so I have a really strange error in my react application.
Basically I have a function that handles an input change and changes the state from the parent component.
import React from "react";
import PaginationExtended from "../PaginationExtended/PaginationExtended";
import { ScreenContext } from "../../helpers/context";
import {
Paper,
TableCell,
TableContainer,
Table,
TableBody,
TableHead,
TableRow,
Checkbox,
TextField,
} from "#material-ui/core";
import EnhancedTableToolbar from "../EnhancedToolBar/EnhancedToolBar";
import uuid from "react-uuid";
import findWithAttr from "../../helpers/findAttr";
import objectInArray from "../../helpers/objectInArray";
import ItemTableRow from "./ItemTableRow/ItemTableRow";
const ItemTable = (props) => {
const screen = React.useContext(ScreenContext);
const handleCheckboxClick = (e) => {
if (e.target.checked) {
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(props.rows, "id", parseInt(e.target.id));
const newRow = {};
props.headings.forEach((heading) => {
newRow[heading.text.toLowerCase()] =
props.rows[rowIndex][heading.default];
});
newRow.id = e.target.id;
newRow.type = "accepted";
newRow.files = [];
newRow.category = props.title;
newTableData.push(newRow);
return newTableData;
});
} else {
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(
newTableData,
"id",
parseInt(e.target.id)
);
newTableData.splice(rowIndex, 1);
return newTableData;
});
}
};
const handleInputChange = () => {
console.log(1);
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(newTableData, "id", props.row.id);
newTableData[rowIndex][e.target.name] = e.target.value;
return newTableData;
});
};
return (
<Paper className={`${props.className}`}>
<EnhancedTableToolbar
screen={screen}
title={props.title}
// record={props.rows}
// setRows={setRows}
/>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
{props.hasCheckbox && <TableCell padding="checkbox" />}
{props.headings.map((heading) => {
return (
<TableCell className={"text-nowrap"} align="right">
{heading.text}
</TableCell>
);
})}
</TableRow>
</TableHead>
<TableBody>
{props.rows.map((row, index) => {
if (!props.inputTable) {
return (
<ItemTableRow
title={props.title}
headings={props.headings}
handleCheckboxClick={handleCheckboxClick}
dynamicRows={props.dynamicRows}
index={index}
row={row}
hasCheckbox={props.hasCheckbox}
setDynamicRows={props.setDynamicRows}
/>
);
} else {
if (row.type === "accepted" && row.category === props.title) {
return (
<ItemTableRow
title={props.title}
headings={props.headings}
handleCheckboxClick={handleCheckboxClick}
dynamicRows={props.dynamicRows}
index={index}
row={row}
hasCheckbox={props.hasCheckbox}
handleInputChange={handleInputChange}
/>
);
}
}
})}
</TableBody>
</Table>
</TableContainer>
{props.hasPagination && (
<PaginationExtended
recordsPerPage={rowsPerPage}
className={"p-3 justify-content-end"}
totalRecords={rows.length}
paginate={handleChangePage}
currentPage={page}
shape={"round"}
/>
)}
</Paper>
);
};
export default ItemTable;
This function is called from a child component of the component at the top.
import React from "react";
import { TableCell, TableRow, Checkbox, TextField } from "#material-ui/core";
import objectInArray from "../../../helpers/objectInArray";
const ItemTableRow = (props) => {
return (
<TableRow key={props.index}>
{props.hasCheckbox && (
<TableCell padding="checkbox">
<Checkbox
id={props.row.id}
checked={objectInArray(
props.dynamicRows,
"id",
props.row.id.toString()
)}
onClick={props.handleCheckboxClick}
// inputProps={{
// "aria-labelledby": `${props.title}-${index}`,
// }}
/>
</TableCell>
)}
{props.headings.map((heading) => {
return (
<TableCell
className={"text-nowrap"}
id={`${props.title}-${props.index}`}
align="right"
>
{heading.isTextInput ? (
<TextField
onChange={props.handleInputChange}
id={`${props.title}-${heading.text}-${props.row.id}`}
type={heading.inputType}
size={"small"}
variant="outlined"
inputProps={{ min: 0 }}
notched={false}
InputLabelProps={{ shrink: false }}
className={`minInputWidth`}
InputProps={{
classes: { input: "py-2 customize-inputField" },
}}
name={heading.text.toLowerCase()}
placeholder={heading.text}
/>
) : (
<p>{props.row[heading.default]}</p>
)}
</TableCell>
);
})}
</TableRow>
);
};
export default ItemTableRow;
When I trigger this event the following error appears in the console.
Uncaught TypeError: props.setDynamicRows is not a function
The curious thing about this is that the handleCheckboxClick function does not throw any error and is also called called from the child component. I have tried reestructuring the components and functions but nothing works.
If someone knows what is happening I would really appreciate the help, thanks.
I came from Vue.js Vuetify.js background.Vuetify.js has v-data-table component.
Simply we pass headers and items to generate a nice table.
<v-data-table
:headers="headers"
:items="desserts"
></v-data-table>
If we want to add a button, image, or something like that to a table cell
What we do is
<v-data-table :headers="headers" :items="items" >
<template v-slot:item.images="{ item }">
<v-img
v-if="item.images"
max-width="150px"
:src="item.images"
contain
></v-img>
</template>
<template v-slot:item.update="{ item }">
<v-btn
#click="
$router.replace({
path: '/create-product',
query: { id: item.id },
})
"
>
<v-icon>edit</v-icon>
</v-btn></template
>
</v-data-table>
This is very clean and easy.
In React.js also I could achieve the first thing using this
export default function ReusableTable({ headers, items }) {
return (
<Grid container>
<Grid item>
<Card>
<CardContent>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
{headers.map((header, i) => (
<TableCell key={i}>{header.text.toUpperCase()}</TableCell>
))}
</TableRow>
</TableHead>{' '}
<TableBody>
{items.map((item, i) => (
<TableRow key={i}>
{headers.map(({ value }) => (
<TableCell key={value}>{item[value]}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</CardContent>
</Card>
</Grid>
</Grid>
);
}
Here also I pass the headers and items.
I want to display buttons, links, images, chips (UI) for certain columns in the table. How do I achieve that in the React world?
If I further explain, I want to pass items array (array of object). Object's imageSRC property should render with an img tag. Something like that.
Something like this should work. This is conditionally rendering an image tag if there is an item.images as stated in your question. Next it will render a Material Button if item.update exists. Alternatively, it simply renders the item[value].
Here is abbreviated code:
export default function ReusableTable({ headers, items }) {
const dynamicRender = (item, value)=>{
if(item && item.images){
return <img src=`${item.images}`/>
} else if(item && item.update){
return <Button href="/create-product">Link</Button>
} else {
return item[value];
}
}
return (
<TableBody>
{items.map((item, i) => (
<TableRow key={i}>
{headers.map(({ value }) => (
<TableCell key={value}>{dynamicRender(item, value)}</TableCell>
))}
</TableRow>
))}
</TableBody>
);
}
Try something like this
import React from "react";
import TableContainer from "#material-ui/core/TableContainer";
import Table from "#material-ui/core/Table";
import Paper from "#material-ui/core/Paper";
import TableHead from "#material-ui/core/TableHead";
import TableRow from "#material-ui/core/TableRow";
import TableCell from "#material-ui/core/TableCell";
import TableBody from "#material-ui/core/TableBody";
import { getSlots } from 'helpers/Slots'
const BaseTable = ({ headers, items, children, ...otherProps }) => {
const [actions] = getSlots(['actions'], children)
const tableConfig = {
size: "small",
}
const rowConfig = {
...otherProps,
}
const dynamicRenderer = (item, value) => {
if (value === 'actions') {
return children(item)
} else {
return item[value]
}
}
return (
<>
<TableContainer component={Paper}>
<Table {...tableConfig}>
<TableHead>
<TableRow {...rowConfig}>
{headers.map((header, i) => (
<TableCell key={i}>{header.label}</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{items.map((item, i) => (
<TableRow key={i} {...rowConfig}>
{headers.map(({ value }) => (
<TableCell key={value}>{dynamicRenderer(item, value)}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
)
}
export default BaseTable
Then added helpers
import React from "react";
const Slot = ({ children }) => <>{children}</>
const getSlots = ( names, children) => {
return names.map(name => {
let slot = null;
React.Children.forEach(children, child => {
if (!React.isValidElement(child)) {
return;
}
if (child.type === Slot && (child.props).name === name) {
slot = React.cloneElement(child);
}
});
return slot;
});
}
export { Slot, getSlots }
import React, { useState, useEffect } from "react"
import Grid from '#material-ui/core/Grid'
import BaseTable from 'helpers/Table'
import { Slot } from 'helpers/Slots'
import PencilBoxOutline from 'mdi-react/PencilBoxIcon'
import DeleteOutline from 'mdi-react/DeleteIcon'
const headers = [
{value: 'name', label: 'Name'},
{value: 'age', label: 'Age'},
{value: 'gender', label: 'Gender'},
{value: 'registeredDate', label: 'Date of Registration'},
{value: 'requirements', label: 'Semester Requirements'},
{value: 'percentage', label: 'Percentage (%)'},
{value: 'actions', label: 'Actions'},
]
const items = [
{
id: 1,
requirements: 'Pay at least 50% ',
percentage: '10%',
name: "John Doe",
age: 30,
registeredDate: "2021/10/30",
gender: "Male"
},
{
id: 2,
requirements: 'Just go with it',
percentage: '50%',
name: "Jane Doe",
age: 40,
registeredDate: "2021/10/30",
gender: "Female"
},
]
const Test = () => {
return (
<Grid container spacing={4}>
<Grid item xs={12}>
<Grid container justifyContent="space-between" spacing={2}>
<Grid item></Grid>
<Grid item sm={9}></Grid>
</Grid>
<BaseTable headers={headers} items={items}>
{(item) => (
<Slot name="actions">
<PencilBoxOutline onClick={(item) => onOpenDialog(item)}/>
<DeleteOutline onClick={(item) => onDelete(item)} />
</Slot>
)}
</BaseTable>
</Grid>
</Grid>
)
}
export default Test
I have a material-ui Table and I'm adding multi-select capability to it. My requirements are as follows.
Checkboxes are all initially hidden. - DONE
When hovering on a row its checkbox appears. DONE
Once one Checkbox is checked then all Checkbox elements on other rows become constantly visible.
I have the first two requirements done but I'm struggling with the final one.
How do I get all checkboxes to be visible (by changing opacity) once any one of them becomes checked ?
This is where I've got to so far :
import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "#material-ui/core/styles";
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 Paper from "#material-ui/core/Paper";
import Checkbox from "#material-ui/core/Checkbox";
const useStyles = makeStyles({
rowIconStyle: {
minWidth: 50,
minHeight: 50
},
tableRowStyle: {
cursor: "pointer",
"&:hover": {
backgroundColor: "darkGrey"
}
},
rowSelectionCheckboxStyle: {
//opacity: "calc(var(--oneRowSelected))",
opacity: 0,
"$tableRowStyle:hover &": {
opacity: 1
}
}
});
export default function MyTableComponent(props) {
const styles = useStyles();
const DEFAULT_TABLE_ROW_ICON_COLOR = "grey";
return (
<TableContainer component={Paper}>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>
<Checkbox className={styles.rowSelectionCheckboxStyle} />
</TableCell>
<TableCell>Icon</TableCell>
<TableCell>Name</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.tableRowsData.map(row => {
const RowIcon =
row.icon && row.icon.iconElement
? row.icon.iconElement
: () => <div />;
let iconElement = (
<RowIcon
className={styles.rowIconStyle}
style={{
color:
row.icon && row.icon.color
? row.icon.color
: DEFAULT_TABLE_ROW_ICON_COLOR
}}
/>
);
return (
<TableRow key={row.name} className={styles.tableRowStyle}>
<TableCell>
<Checkbox className={styles.rowSelectionCheckboxStyle} />
</TableCell>
<TableCell>{iconElement}</TableCell>
<TableCell>{row.projectName}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
);
}
MyTableComponent.propTypes = {
tableRowsData: PropTypes.array
};
Have a value and an onChange in your Checkbox. Maintain a state which represents the selected checkboxes and update it upon onChange. Check the checkboxes array and only attach the class styles.rowSelectionCheckboxStyle if any one checkbox is checked.
Working copy of your code is here
export default function MyTableComponent(props) {
const [checkedRows, setCheckedRows] = useState({});
const styles = useStyles();
const DEFAULT_TABLE_ROW_ICON_COLOR = "grey";
const anyChecked = () => {
let anyRowChecked = false;
for (let key in checkedRows) {
if (checkedRows[key]) {
anyRowChecked = true;
}
}
return anyRowChecked;
};
const checked = (checked, index) => {
setCheckedRows(prev => ({ ...prev, [index]: checked }));
};
...
...
return (
<TableRow key={row.name} className={styles.tableRowStyle}>
<TableCell>
<Checkbox
checked={checkedRows[index]}
onChange={e => checked(e.target.checked, index)}
className={
!anyChecked() && styles.rowSelectionCheckboxStyle
}
/>
</TableCell>
<TableCell>{iconElement}</TableCell>
<TableCell>
{checkedRows[index] ? "True" : "False"} {row.projectName}
</TableCell>
</TableRow>
);
})}
...