Collapsing Table Row Collapses all Rows - reactjs

I have a state to check if collapse is true or false
const [open, setOpen] = useState(false);
then returns on render:
<TableBody> {isCityReady && cities ? (cities.map((row, index) => (
<TableRow key={index} sx={{ borderBottom: "2px solid black", "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell component="th" scope="row" align="left">
<Typography variant="body1" fontWeight="bold">
{row.city}
</Typography>
</TableCell>
<TableCell>
<Collapse in={open} timeout="auto" unmountOnExit>
<Typography variant="body1" fontWeight="bold">
{isReady && locations ? (locations.filter(rowLocation => rowLocation.city === row.city).map((rowLocation, indexLocation) => (
<TableRow key={indexLocation} sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell style={{ width: '100%' }}>
<Typography variant="body1">
{rowLocation.office}
</Typography>
</TableCell>
<TableCell align="right" style={{ width: '100%' }}>
<Button variant="contained" color="primary" onClick={() => handleOpenLocationsDialog("Edit", rowLocation.city, rowLocation.office, rowLocation.id)}>
Edit
</Button>
</TableCell>
</TableRow>
))) : (<LocationsTableSkeleton />)}
</Typography>
</Collapse>
</TableCell>
</TableRow>
))
) : (
<LocationsTableSkeleton />
)}
every row would collapse/uncollapse simultanously. How do I make it so that only the row that was clicked would collpase?

You need to keep a flag for each row.
something like the following
const [openCities, setOpenCities] = useState({});
const toggleCity = useCallback((city)=>{
setOpenCities(state => ({
...state,
[city]: !Boolean(state[city])
}));
},[]);
then returns on render:
<TableBody> {isCityReady && cities ? (cities.map((row, index) => {
// extract the flag/state of the specific city
const open = Boolean(openCities[row.city]);
return (
<TableRow key={index} sx={{ borderBottom: "2px solid black", "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => toggleCity(row.city)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
......
<TableCell>
<Collapse in={open} timeout="auto" unmountOnExit>
.....

Related

How to change dropdown in each row of mui table cell in a loop?

import * as React from "react";
import {
Select,
MenuItem,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper
} from "#mui/material";
import KeyboardArrowDownIcon from "#mui/icons-material/KeyboardArrowDown";
function createData(name, mobile, access) {
return { name, mobile, access };
}
const rows = [
createData("Sam", 9865745159),
createData("Amily", 8723879237),
createData("Eva", 9432671262),
createData("Jack", 7898083305),
createData("Diana", 8973667356)
];
export default function DenseTable() {
const [access, setAccess] = React.useState(1);
const handleChange = (event, index, data) => {
setAccess(event.target.value);
};
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<TableCell align="center">Name</TableCell>
<TableCell align="center">Mobile</TableCell>
<TableCell align="center">Access</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow
key={row.name}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell component="th" scope="row" align="center">
{row.name}
</TableCell>
<TableCell align="center">{row.mobile}</TableCell>
<TableCell align="center">
<Select
value={access}
onChange={handleChange}
MenuProps={{
MenuListProps: { disablePadding: true }
}}
fullWidth
size="small"
IconComponent={() => (
<KeyboardArrowDownIcon
sx={{
position: "absolute",
right: 10,
width: "20px",
pointerEvents: "none"
}}
/>
)}
sx={{
fontSize: "14px",
width: "100px",
height: "28px"
}}
>
<MenuItem
value={1}
sx={{
fontSize: "14px",
height: "25px",
width: "100%"
}}
>
Allow
</MenuItem>
<MenuItem
value={2}
sx={{
fontSize: "14px",
height: "30px",
width: "100%"
}}
>
Decline
</MenuItem>
</Select>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
I am using ReactJs with Material UI table with dropdown in each row of the table cell. Whenever I am changing the dropdown option of one row then automatically changes to same option in dropdown of all rows.I have to handle each row separately. How to change dropdown in each row of mui table cell in a loop? file.
Move the dropdown to a new jsx component and manage the state there
function dropdownComponent (){
const [access, setAccess] = React.useState(1);
const handleChange = (event, index, data) => {
setAccess(event.target.value);
};
return
(<Select
value={access}
onChange={handleChange}
MenuProps={{
MenuListProps: { disablePadding: true }
}}
fullWidth
size="small"
IconComponent={() => (
<KeyboardArrowDownIcon
sx={{
position: "absolute",
right: 10,
width: "20px",
pointerEvents: "none"
}}
/>
)}
sx={{
fontSize: "14px",
width: "100px",
height: "28px"
}}
>
<MenuItem
value={1}
sx={{
fontSize: "14px",
height: "25px",
width: "100%"
}}
>
Allow
</MenuItem>
<MenuItem
value={2}
sx={{
fontSize: "14px",
height: "30px",
width: "100%"
}}
>
Decline
</MenuItem>
</Select>
)
}
Call it like this
<TableCell align="center">
<dropdownComponent />

list should have a unique "key" prop

I get this error even though I put a key.
react_devtools_backend.js:4026 Warning: Each child in a list should have a unique "key" prop.
Shows here a picture of the error
Showing the code here :
return (
<div>
<div style={{ textAlign: "center" }}>
{players?.length > 0 && (
<div style={{ marginTop: "2rem" }}>
<h2>Results "{query}"</h2>
<TableContainer
component={Paper}
style={{
marginLeft: "auto",
marginRight: "auto",
width: "90%",
}}
>
<Table sx={{ minWidth: 350 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Full Name</TableCell>
<TableCell>Club</TableCell>
<TableCell>Nation</TableCell>
<TableCell>Position</TableCell>
<TableCell>Age</TableCell>
<TableCell>Market Value</TableCell>
<TableCell>Favorite</TableCell>
</TableRow>
</TableHead>
<TableBody>
{players.map((item) => {
return <TableRow
key={item.id}
sx={{
"&:last-child td, &:last-child th": { border: 0 },
}}
style={{ textAlign: "center" }}
>
<TableCell>
<ListItem>
<Link
onClick={() => pickPlayer(item.id)}
style={{ textDecoration: "none" }}
to={`/player/${item.id}`}
>
{item?.img !== "https://img.a.XXX.technology/portrait/header/default.jpg?lm=1" &&
<img
src={item?.img}
alt={item?.displayName}
style={{ marginRight: "5px" , width: '2.5rem' , borderRadius: '80%' }}
/>
}
{item?.img === "https://img.a.XXX.technology/portrait/header/default.jpg?lm=1" &&
<img
src={'https://www.seekpng.com/png/full/202-2024994_profile-icon-profile-logo-no-background.png'}
alt={item?.displayName}
style={{ marginRight: "5px" , width: '3rem'}}
/>
}
<span style={{ verticalAlign: "1rem" }}>
{item?.displayName}
</span>
</Link>
</ListItem>
</TableCell>
<TableCell>
<ListItem>
<img
src={`https://tmssl.akamaized.net/images/wappen/head/${item?.imgId}.png?lm=1457423031`}
alt={item?.club}
title={item?.club}
style={{ marginRight: "2px" , width: '1.7rem' }}
/>{" "}
{item?.club}
</ListItem>
</TableCell>
<TableCell>
{item?.nationality.map((item) => {
return (
<>
<ListItem key={uuidv4()}>
<img
key={uuidv4()}
src={item?.flag}
alt={item?.title}
title={item?.title}
style={{ marginRight: "5px" , width : '1.7rem' , borderRadius : '10rem' }}
/>{" "}
{item.title}
</ListItem>
</>
);
})}
</TableCell>
<TableCell>
<ListItem>{item.position}</ListItem>
</TableCell>
<TableCell>
<ListItem>{item.age}</ListItem>
</TableCell>
<TableCell>
<ListItem>{item.tmValue}</ListItem>
</TableCell>
<TableCell>
<ListItem>
{
favoriteLoading ? "loading..." :
<>
{
favorite.find(fav => fav.playerId === item.id && fav.scoutId === auth._id) !== undefined ? <Favorite style={{ color: "red" }} /> : <FavoriteBorder style={{ color: "red" }} />
}
</>
}
</ListItem>
</TableCell>
</TableRow>
}
)}
</TableBody>
</Table>
</TableContainer>
</div>
)}
{playersLoading && players?.length === 0 ? progress : players?.length === 0 && <h3>{query} Not Found</h3> }
{playersLoading && players?.length > 0 && progress}
{playersLoading && players?.length === 0 ? null : players.length <= 3 && <div style={{height : "20vh"}}>
{
!underThree && <h4>Scroll Down to load more</h4>
}
</div>}
</div>
</div>
);
what can we do ?
I have tried until now to maybe even use an external dynamic uuid to check if the Id is repeating itself and this is not the case.
Because everything seems fine to me.
The problem is in this code:
{item?.nationality.map((item) => {
return (
<>
<ListItem key={uuidv4()}>
<img
key={uuidv4()}
src={item?.flag}
alt={item?.title}
title={item?.title}
style={{ marginRight: "5px" , width : '1.7rem' , borderRadius : '10rem' }}
/>{" "}
{item.title}
</ListItem>
</>
);
})}
The key must be on the outermost element. Your outermost element is a fragment <>, which has no key. If you don't need the fragment you can delete it and have the ListItem be the outermost element.
If you do need to have a fragment on the outside, you can use the longhand form of fragments to add a key to it:
import { Fragment } from 'react';
// ...
return (
<Fragment key={/* insert key here */}>
<ListItem>
<img
src={item?.flag}
alt={item?.title}
title={item?.title}
style={{ marginRight: "5px" , width : '1.7rem' , borderRadius : '10rem' }}
/>{" "}
{item.title}
</ListItem>
</Fragment>
)
By the way, calling uuidv4() as you're doing for the key is going to create a brand new key on every render. This is going to force every list item to unmount and remount on every render. The keys should ideally be a piece of data on the item. If that's not an option, then the index could be used as a last resort. But don't use random keys that change on every render.
Check your file where you have defined item if there is any repeated number or anything in your item.id.
Or you can also give it Math.random(); like:
{players.map((item) => {
return <TableRow
key={Math.floor(Math.random)}
...
</TableRow>
}

MaterialUI React Table -> Diver Color and Page Dropdown colors

I am trying to change the divider color in my TableBody, and also the background color of the Rows per page dropdown menu. Any help is appreciated, thank you!
I am using styled-components ThemeProvider to toggle the theme in my app, so I am passing this hook as a prop for MUI components and adjusting their colors with this method:
props.theme === 'light' ? '#fff' : '#2a2a2a'
<Box sx={{ width: '99.5%' }}>
<Paper sx={{ width: '100%', mb: 2 }}>
<EnhancedTableToolbar theme={props.theme} numSelected={selected.length} />
<TableContainer>
<Table
sx={{ minWidth: 750, background: props.theme === 'light' ? '#fff' : '#2a2a2a' }}
aria-labelledby="tableTitle"
size={dense ? 'small' : 'medium'}
>
<EnhancedTableHead
sx={{ background: props.theme === 'light' ? '#fff' : '#2a2a2a' }}
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={rows.length}
/>
<TableBody>
{/* if you don't need to support IE11, you can replace the `stableSort` call with:
rows.slice().sort(getComparator(order, orderBy)) */}
{stableSort(rows, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
const isItemSelected = isSelected(row.macid);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.macid}
selected={isItemSelected}
>
<TableCell
component="th"
id={labelId}
scope="row"
>
{row.macid}
</TableCell>
<TableCell align="right">{row.cpu}</TableCell>
<TableCell align="right">{row.ram}</TableCell>
<TableCell align="right">{row.disk}</TableCell>
<TableCell align="right">{row.temperature}</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow
style={{
height: (dense ? 33 : 53) * emptyRows,
}}
>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
sx={{background: props.theme === 'light' ? '#fff' : '#2a2a2a'}}
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Paper>
<FormControlLabel
control={<Switch checked={dense} onChange={handleChangeDense} />}
label="Dense padding"
/>
</Box>
Have you tried props.theme.background?

Onchange is not working when editing cell of material-table in react.js

how can I make an editable cell in React with Material-UI? I'm trying to make cell editable in material UI table but when I pass inputChangeHandler to onChange method it doesn't work as expected, the text just adds to the new row.
snapshot:
the edited data shifted to the new table row
I am using react-hooks useState to store the initial state.
code:
const MyForm = () => {
const [data, setdata] = useState([
{
id: 1,
name: "Frozen yoghurt",
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
},
{
id: 2,
name: "Ice cream sandwich",
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
},
{ id: 3, name: "Eclair", calories: 300, fat: 7.0, carbs: 67, protein: 4 },
{
id: 4,
name: "Velvet cake",
calories: 237,
fat: 2.5,
carbs: 17,
protein: 3,
}
]);
const [editingIndex, setEditingIndex] = useState(-1);
const addNewUserHandler = () => {
let newData = [{
id: "",
name: "",
calories: "",
fat: "",
carbs: "",
protein: ""
}];
const Data = data;
// Data.push(newData)
console.log(newData)
setdata([...Data, newData])
};
const addNewData = e => {
console.log(e);
};
// const editDataHandler = id => {
// // console.log(id);
// // setEditing(true)
// setEditingIndex(id)
// };
const startEditing = i => {
setEditingIndex(i);
};
const stopEditing = () => {
setEditingIndex(-1);
};
const inputChangeHandler = (e) => {
// e.persist();
// console.log(id, e.target.value, "e,target");
setdata([{[e.target.name]: e.target.value}])
};
const submitInputHandler = (e) => {
e.persist();
console.log("this is the input change handler", e.target.value);
};
const deleteRowHandler = id => {
const temp = [...data];
const filteredData = temp.filter(data => data.id !== id);
setdata([...filteredData,]);
};
const classes = useStyles();
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<Table className={classes.table} size="small">
<TableHead>
<TableRow>
<TableCell>Id.</TableCell>
<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>
<TableCell align="right">
<InputBase
placeholder="search"
inputProps={{ "aria-label": "search" }}
style={{ verticalAlign: "middle" }}
/>
<SearchIcon style={{ verticalAlign: "middle" }} />
</TableCell>
<TableCell align="right">
<Tooltip title="Add data" aria-label="add">
<Fab
color="primary"
className={classes.fab}
onClick={addNewUserHandler}
>
<AddIcon />
</Fab>
</Tooltip>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map((data, id) => (
<TableRow key={id}>
{editingIndex === data.id ? (
<TableCell component="th" scope="row">
<TextField
style={{ width: "3rem" }}
name="id"
onChange={(e) =>inputChangeHandler(e)}
value={id+1}
/>
</TableCell>
) :
(
<TableCell component="th" scope="row">
{id+1}
</TableCell>
)}
{editingIndex === data.id ? (
<TableCell>
<TextField
style={{ width: "8rem" }}
onChange={(e) =>inputChangeHandler(e)}
name="name"
value={data.name}
/>
</TableCell>
) : (
<TableCell style={{ textAlign: "center" }}>
{data.name}
</TableCell>
)}
{editingIndex === data.id ? (
<TableCell align="center">
<TextField
style={{ width: "8rem" }}
onChange={(e) =>inputChangeHandler(e)}
name="calories"
value={data.calories}
/>
</TableCell>
) : (
<TableCell style={{ textAlign: "center" }}>
{data.calories}
</TableCell>
)}
{editingIndex === data.id ? (
<TableCell>
<TextField
style={{ width: "8rem" }}
onChange={(e) =>inputChangeHandler(e)}
name="fat"
value={data.fat}
/>
</TableCell>
) : (
<TableCell style={{ textAlign: "center" }}>
{data.fat}
</TableCell>
)}
{editingIndex === data.id ? (
<TableCell align="center">
<TextField
style={{ width: "8rem" }}
onChange={(e) =>inputChangeHandler(e)}
name="carbs"
value={data.carbs}
/>
</TableCell>
) : (
<TableCell style={{ textAlign: "center" }}>
{data.carbs}
</TableCell>
)}
{editingIndex === data.id ? (
<TableCell align="center">
<TextField
disabled={false}
style={{ width: "8rem" }}
onChange={(e) =>inputChangeHandler(e)}
name="protein"
value={data.protein}
/>
</TableCell>
) : (
<TableCell style={{ textAlign: "center" }}>
{data.protein}
</TableCell>
)}
<TableCell style={{ textAlign: "center" }}>
{editingIndex !== data.id ? (
<EditIcon onClick={() => startEditing(data.id)} style= {{cursor: "pointer"}}/>
) : (
<CheckIcon onClick={submitInputHandler} style= {{cursor: "pointer"}} />
)}
</TableCell>
<TableCell>
{editingIndex !== data.id ? (
<DeleteIcon onClick={() => deleteRowHandler(data.id)} style= {{cursor: "pointer"}}/>
) : (
<CloseIcon onClick={stopEditing} style= {{cursor: "pointer"}} />
)}
</TableCell>
</TableRow>
))}
{/* <TableRow>
<TablePagination
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
/>
</TableRow> */}
</TableBody>
</Table>
</Paper>
</div>
);
};
export default MyForm;
const inputChangeHandler = (e, id) => {
let result = data.map((data, id) =>{
return data.id == id ? {...data, name:e.target.value} : {...data}
})
setdata(result)
}
//then
onChange={(e) =>inputChangeHandler(e, data.id)}

Autocomplete react-select bad styles

I'm using react-select autocomplete component for my react js web site. I just copied the example code in this link inside to a table cell, but it is not working properly as shown in the below image.
However, it individually works fine. Please help me with this issue. Here is the code.
Autocomplete.jsx has the same code as in the above link.
...
import Autocomplete from './Autocomplete.jsx';
...
const useStyles = makeStyles(theme => ({
textField: {
padding: theme.spacing(),
width: '100%',
},
}));
...
export default function Mapping(props) {
const classes = useStyles();
...
return (
<TableRow>
<TableCell>
<TextField
required
id='outlined-required'
label='URL pattern'
variant='outlined'
value={name}
onChange={event => setName(event.target.value)}
className={classes.textField}
/>
</TableCell>
<TableCell>
<Autocomplete arn={arn} setArn={setArn} />
</TableCell>
{resource.editable ?
<TableCell>
<Button onClick={saveResource}>Save</Button>
<Button onClick={cancel}>Cancel</Button>
</TableCell>
:
<TableCell>
<Button onClick={addResource}>Add</Button>
</TableCell>
}
</TableRow>
);
}
=========================================================================
...
import Mapping from './Mapping.jsx';
...
const useStyles = makeStyles(theme => ({
root: {
paddingBottom: theme.spacing(),
paddingTop: theme.spacing(),
width: '100%',
marginTop: theme.spacing(),
},
mappingsWrapper: {
padding: theme.spacing(),
borderRight: '#c4c4c4',
borderRightStyle: 'solid',
borderRightWidth: 'thin',
},
mappingsHeading: {
display: 'flex',
alignItems: 'center',
},
mappingsTitle: {
paddingLeft: theme.spacing(),
fontSize: '1rem',
paddingTop: theme.spacing(),
paddingBottom: theme.spacing(),
},
}));
...
export default function Mappings() {
const classes = useStyles();
...
return (
<Paper className={classes.root}>
<Grid container item xs={12}>
<Grid xs className={classes.mappingsWrapper}>
<div className={classes.mappingsHeading}>
<Typography className={classes.mappingsTitle}>
Mappings
</Typography>
</div>
<Table stickyHeader>
<TableHead>
<TableRow>
{columns.map(column => (
<TableCell
key={column.id}
align={column.align}
style={{ minWidth: column.minWidth }}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{resources.map((resource) => {
if (resource.editable) {
return (
<Mapping
resource={resource}
resources={resources}
setResources={setResources}
/>
);
} else {
return (
<TableRow>
<TableCell>{resource.name}</TableCell>
<TableCell>{resource.arn}</TableCell>
<TableCell>
<Button onClick={() => editResource(resource)}>Edit</Button>
<Button onClick={() => deleteResource(resource)}>Delete</Button>
</TableCell>
</TableRow>
);
}
})}
<Mapping
resource={{ name: '', arn: '', editable: false }}
resources={resources}
setResources={setResources}
/>
</TableBody>
</Table>
</Grid>
</Grid>
</Paper>
);
}

Resources