How to check map has values or not react - reactjs

I have a list users, those details want to show in table format. Want to check if map has value, if not show the message 'no data found'.
how can I achieve that.?
{filteredList && filteredList
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map(row =>
( row===null ? (
<TableRow key={row.id}>
<TableCell className={classes.tableCell}>{items++}</TableCell>
<TableCell className={classes.tableCell}>
{row.sp_Name}
</TableCell>
<TableCell className={classes.tableCell}>{row.sp_Phone}</TableCell>
<TableCell className={classes.tableCell}>{row.sp_Role}</TableCell>
<TableCell className={classes.tableCell}>{row.sp_Service}</TableCell>
<TableCell className={classes.tableCell}>{row.sp_Location}</TableCell>
<TableCell className={classes.tableCell}>
<Link to={'/admin/profile/' + row.id} key={row.id} style={{ textDecoration: "none" }} >
<Chip
icon={<FaceIcon />}
label="View Profile/Action"
color="primary"
className={classes.chip}
variant="outlined"
onClcik={this.handleAction}
/>
</Link>
</TableCell>
<TableCell className={classes.tableCell}>
<Tooltip title="Delete">
<DeleteIcon color="danger" onClick={() => this.handleClickDialogOpen(row.id)} className={classes.icon} />
{/* <DeleteIcon onClick={() => deleteSP(row.id)} className={classes.icon} /> */}
</Tooltip>
</TableCell>
</TableRow>
) : "no data"
)
)}

Your can check if data exist first, if yes, render the table and row. If no data,
then you just render the required 'no data found' text
getData = () => {
const filteredList = this.state.list // your logic to get data
// Perform your logic to filter the data
return filteredList.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
}
render() {
const filteredList = this.getData()
return (
filteredList.length > 0 ?
<table>
{data.map( /* Make your <tr> */ )}
</table> :
"no data found"
)
}

Related

sortDirection prop of TableCell doesn't work

I have a table with items. I use cookies to save them. Also, I have two buttons (increase and decrease). When I press them to change qty it works, but it also puts the item's row to the bottom of the list. I need to keep them in the same position where they are. I used sortDirection prop to TableCell component to make an order, but it also didn't work. Please help update the code so I can keep items in the same position.
Thanks in advance.
export default function CartItemsTable() {
const [cookies, setCookie, removeCookie] = useCookies();
function IncreaseQTY(article) {
var newCookie = cookies[article];
newCookie.qty++;
setCookie(article, newCookie, {
expires: new Date(Date.now() + 604800000),
});
}
function DecreaseQTY(article) {
var newCookie = cookies[article];
newCookie.qty--;
if (newCookie.qty === 0) {
removeCookie(article);
} else {
setCookie(article, newCookie, {
expires: new Date(Date.now() + 604800000),
});
}
}
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} >
<TableHead>
<TableRow>
<TableCell >Name</TableCell>
<TableCell sortDirection="asc" align="center">Code</TableCell>
<TableCell align="center">Price</TableCell>
<TableCell align="center">QTY</TableCell>
<TableCell align="center">Total</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.keys(cookies).map(function (key, index) {
return (
<TableRow
key={index}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell component="th" scope="row">
{cookies[key].name}
</TableCell>
<TableCell align="center">{cookies[key].article}</TableCell>
<TableCell align="center">{cookies[key].price}</TableCell>
<TableCell align="center">
<ButtonGroup
variant="contained"
aria-label="outlined primary button group"
>
<Button
onClick={() => {
DecreaseQTY(cookies[key].article);
}}
>
-
</Button>
<Button variant="text" disableRipple={true}>
{cookies[key].qty}
</Button>
<Button
onClick={() => {
IncreaseQTY(cookies[key].article);
}}
>
+
</Button>
</ButtonGroup>
</TableCell>
<TableCell align="center">
{cookies[key].qty * cookies[key].price}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
);
}
Before I press the button
After I press the increase button, first line went to the bottom
Update
I guess this problem can be occurred because of the cookies order or even related to react-cookie package, so I added console.log(cookies); to IncreaseQTY function. After a couple increasing it starts to show this way

Chip Component doesn't show up

const ResultsAccordion = ({projects, projectStatus}) =>
{
return (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel1a-content" id="panel1a-header">
<Typography>{projectStatus}</Typography>
</AccordionSummary>
<AccordionDetails>
<TableContainer component={Paper} sx={{my:2 }}>
<Table>
<TableHead>
<TableRow style={{ width:"100%" }}>
<TableCell align="center">Team Name</TableCell>
<TableCell align="center">Project Link</TableCell>
<TableCell align="center">Team Members</TableCell>
</TableRow>
</TableHead>
<TableBody>
{
projects.map((value) =>
{
return (
<TableRow key={value.name}>
<TableCell align="center">
{value.name}
</TableCell>
<TableCell align="center">
<Link href={value.repo}>Project Repo</Link>
</TableCell>
<TableCell align="center">
<Stack direction="row" spacing={1} alignContent="center">
{
(value.members).map((item, key) =>
{
return (
<Chip key={key} component="a" href={`https://github.com/${item.github}`} clickable label={item.github} avatar={<Avatar alt={item.github} src={item.avatar}/> } />
);
})
}
</Stack>
</TableCell>
</TableRow>
);
})
}
</TableBody>
</Table>
</TableContainer>
</AccordionDetails>
</Accordion>
);
};
Chips are supposed to be returned in the Table Cell with Stack..
But there is no one.
I used the react Developers tools and there is no childrens in Stack.
The chips are rendered if i made any changes in the prop using ReactDevTools
I checked, the value.members array & it is also not empty.

ReactJs: Warning: Each child in a list should have a unique "key" prop

I am doing a project in order to run a contracting company and somewhere I have to show all the receipts for each user of the company, but I got this error:
Warning: Each child in a list should have a unique "key" prop.
Although I looked at the code, I didn't find any errors
How can I solve the problem?
Through this file, I display a table, and this table displays a list of receipts
import FuseScrollbars from "#fuse/core/FuseScrollbars";
import _ from "#lodash";
import Checkbox from "#material-ui/core/Checkbox";
import Icon from "#material-ui/core/Icon";
import Table from "#material-ui/core/Table";
import TableBody from "#material-ui/core/TableBody";
import TableCell from "#material-ui/core/TableCell";
import TablePagination from "#material-ui/core/TablePagination";
import TableRow from "#material-ui/core/TableRow";
import Typography from "#material-ui/core/Typography";
import clsx from "clsx";
import { motion } from "framer-motion";
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { withRouter } from "react-router-dom";
import FuseLoading from "#fuse/core/FuseLoading";
import {
getSalaryScales,
selectSalaryScales,
} from "../store/salaryScalesSlice";
import SalaryScalesTableHead from "./SalaryScalesTableHead";
import Moment from "react-moment";
import IconButton from "#material-ui/core/IconButton";
import KeyboardArrowDownIcon from "#material-ui/icons/KeyboardArrowDown";
import KeyboardArrowUpIcon from "#material-ui/icons/KeyboardArrowUp";
function SalaryScalesTable(props) {
const dispatch = useDispatch();
const salaryScales = useSelector(selectSalaryScales);
const searchText = useSelector(
({ salaryScalesApp }) => salaryScalesApp.salaryScales.searchText
);
const [loading, setLoading] = useState(true);
const [selected, setSelected] = useState([]);
const [data, setData] = useState(salaryScales);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [order, setOrder] = useState({
direction: "asc",
id: null,
});
const [open, setOpen] = useState(false);
console.log("order: ", order);
useEffect(() => {
dispatch(getSalaryScales()).then(() => setLoading(false));
}, [dispatch]);
useEffect(() => {
if (searchText.length !== 0) {
setData(
_.filter(salaryScales, (item) =>
item.id.toLowerCase().includes(searchText.toLowerCase())
)
);
setPage(0);
} else {
setData(salaryScales);
}
}, [salaryScales, searchText]);
function handleRequestSort(event, property) {
const id = property;
let direction = "desc";
if (order.id === property && order.direction === "desc") {
direction = "asc";
}
setOrder({
direction,
id,
});
}
function handleSelectAllClick(event) {
if (event.target.checked) {
setSelected(data.map((n) => n.id));
return;
}
setSelected([]);
}
function handleDeselect() {
setSelected([]);
}
function handleClick(item) {
props.history.push(`/apps/salary-scales-section/salary-scales/${item.id}`);
}
function handleCheck(event, id) {
const selectedIndex = selected.indexOf(id);
let newSelected = [];
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, id);
} 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);
}
function handleChangePage(event, value) {
setPage(value);
}
function handleChangeRowsPerPage(event) {
setRowsPerPage(event.target.value);
}
if (loading) {
return <FuseLoading />;
}
if (data.length === 0) {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { delay: 0.1 } }}
className="flex flex-1 items-center justify-center h-full"
>
<Typography color="textSecondary" variant="h5">
There are no Salary Scales!
</Typography>
</motion.div>
);
}
return (
<div className="w-full flex flex-col">
<FuseScrollbars className="flex-grow overflow-x-auto">
<Table stickyHeader className="min-w-xl" aria-label="collapsible table">
<SalaryScalesTableHead
selectedSalaryScaleIds={selected}
order={order}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={data.length}
onMenuItemClick={handleDeselect}
/>
<TableBody>
{_.orderBy(
data,
[
(o) => {
switch (order.id) {
case "categories": {
return o.categories[0];
}
default: {
return o[order.id];
}
}
},
],
[order.direction]
)
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((n) => {
const isSelected = selected.indexOf(n.id) !== -1;
return (
<>
<TableRow
className="h-72 cursor-pointer"
hover
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={n.id}
selected={isSelected}
onClick={(event) => handleClick(n)}
>
<TableCell
className="w-40 md:w-64 text-center"
padding="none"
>
<Checkbox
checked={isSelected}
onClick={(event) => event.stopPropagation()}
onChange={(event) => handleCheck(event, n.id)}
/>
</TableCell>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
className="w-40 md:w-64 text-center"
padding="none"
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="left"
>
{n.id}
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
<Moment>{n.createdAt}</Moment>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
{n.isActive ? (
<Icon className="text-green text-20">
check_circle
</Icon>
) : (
<Icon className="text-red text-20">
remove_circle
</Icon>
)}
</TableCell>
</TableRow>
</>
);
})}
</TableBody>
</Table>
</FuseScrollbars>
<TablePagination
className="flex-shrink-0 border-t-1"
component="div"
count={data.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
"aria-label": "Previous Page",
}}
nextIconButtonProps={{
"aria-label": "Next Page",
}}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</div>
);
}
export default withRouter(SalaryScalesTable);
Your problem is from <><TableRow key={n.id}></TableRow></>
In your case, I think you don't need to have <></>, so you can get rid of that, your key missing problem will be solved
return (
<TableRow
className="h-72 cursor-pointer"
hover
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={n.id}
selected={isSelected}
onClick={(event) => handleClick(n)}
>
<TableCell
className="w-40 md:w-64 text-center"
padding="none"
>
<Checkbox
checked={isSelected}
onClick={(event) => event.stopPropagation()}
onChange={(event) => handleCheck(event, n.id)}
/>
</TableCell>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
className="w-40 md:w-64 text-center"
padding="none"
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="left"
>
{n.id}
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
<Moment>{n.createdAt}</Moment>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
{n.isActive ? (
<Icon className="text-green text-20">
check_circle
</Icon>
) : (
<Icon className="text-red text-20">
remove_circle
</Icon>
)}
</TableCell>
</TableRow>
If you want to maintain <></> (as the shortcut for <React.Fragment></React.Fragment>). You need to explicitly call
<React.Fragment key={n.id}>
<TableRow></TableRow>
</React.Fragment>
List must have a unique key while mapping. The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys.
YourArray
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((n) => {
const isSelected = selected.indexOf(n.id) !== -1;
return (
<React.Fragment key={n.id}>
<TableRow
className="h-72 cursor-pointer"
hover
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={n.id}
selected={isSelected}
onClick={(event) => handleClick(n)}
>
<TableCell
className="w-40 md:w-64 text-center"
padding="none"
>
<Checkbox
checked={isSelected}
onClick={(event) => event.stopPropagation()}
onChange={(event) => handleCheck(event, n.id)}
/>
</TableCell>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
className="w-40 md:w-64 text-center"
padding="none"
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="left"
>
{n.id}
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
<Moment>{n.createdAt}</Moment>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
{n.isActive ? (
<Icon className="text-green text-20">
check_circle
</Icon>
) : (
<Icon className="text-red text-20">
remove_circle
</Icon>
)}
</TableCell>
</TableRow>
</React.Fragment>
);
})
Here you must give key to first div:
return (
<div key={n.id}>
<TableRow
className="h-72 cursor-pointer"
hover
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
selected={isSelected}
onClick={(event) => handleClick(n)}
>
<TableCell
className="w-40 md:w-64 text-center"
padding="none"
>
<Checkbox
checked={isSelected}
onClick={(event) => event.stopPropagation()}
onChange={(event) => handleCheck(event, n.id)}
/>
</TableCell>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
className="w-40 md:w-64 text-center"
padding="none"
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="left"
>
{n.id}
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
<Moment>{n.createdAt}</Moment>
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="center"
>
{n.isActive ? (
<Icon className="text-green text-20">
check_circle
</Icon>
) : (
<Icon className="text-red text-20">
remove_circle
</Icon>
)}
</TableCell>
</TableRow>
</div>
);

Material UI Accordion Summary

I have a very peculiar case to display Selected Item Count in my Material UI - Accordion Summary:
Following Should be the Behavior:
When a User click on the Header Checkbox it should select All the Item in that Panel and then shows the Count of those Items as X Selected
Right Now I am able to do the following :
As You can see the Number of Items selected is showing on Each Panel But I only Want it to show in the Selected Panel.
Below is my Code for Above screen Shot:
{unsubscribedEmployeeData ? Object.entries(unsubscribedEmployeeData).map(([name, value]) => {
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions1-content"
id="additional-actions1-header"
>
<EnhancedTableToolbar numSelected={selected.length} name={name} values={value} />
</AccordionSummary>
<AccordionDetails>
<Typography color="textSecondary">
<div className={classes.root}>
<Paper className={classes.paper}>
<TableContainer>
<Table
className={classes.table}
aria-labelledby="tableTitle"
size={dense ? 'small' : 'medium'}
aria-label="enhanced table"
>
<TableBody>
{stableSort(value, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
const isItemSelected = isSelectedID(row.id);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
onClick={(event) => handleClick(event, row.first_name + " " + row.last_name, row.id)}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.id}
selected={isItemSelected}
>
<TableCell padding="checkbox">
<Checkbox
checked={isItemSelected}
inputProps={{ 'aria-labelledby': labelId }}
/>
</TableCell>
<TableCell align="center" component="th" id={labelId} scope="row" >
{row.first_name + " " + row.last_name}
</TableCell>
<TableCell align="center">{row.email}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
</Paper>
</div>
</Typography>
</AccordionDetails>
</Accordion>
);
}) : undefined}
EnhancedTableToolbar
const EnhancedTableToolbar = (props) => {
const classes = useToolbarStyles();
const { numSelected, name, values } = props;
return (
<Toolbar
className={clsx(classes.root)}
>
{numSelected > 0 ? (
<>
<EnhancedTableHead
classes={classes}
numSelected={selected.length}
onSelectAllClick={(event) => handleSelectAllClick(event,values)}
rowCount={values.length}
label={name}
/>
<Typography component="div">
{numSelected} selected
</Typography>
</>
) : (
<EnhancedTableHead
classes={classes}
numSelected={selected.length}
onSelectAllClick={(event) => handleSelectAllClick(event,values)}
rowCount={values.length}
label={name}
/>
)}
</Toolbar>
);
};
handleSelectAllClick
const handleSelectAllClick = (event, val) => {
if (event.target.checked) {
const newSelectedsID = val.map((n) => n.id);
const newSelecteds = val.map((n) => n.first_name + " " + n.last_name);
console.log(newSelecteds);
console.log(newSelectedsID);
setSelectedID(newSelectedsID);
setSelected(newSelecteds);
return;
}
setSelected([]);
setSelectedID([]);
};
Please guide me through this. Thanks

Warning: React has detected a change in the order of Hooks called by null

The function is called on form submission. at first, it is working as expected but when calling this function on form submit. I get this following error.index.js:1 Warning: React has detected a change in the order of Hooks called by null. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks:
Previous render Next render
useState useState
undefined useState
Here is the code sample :
function TablerowsAdd ( x,i,header,handleRemove, startEditing,editIdx,handleChange,stopEditing,handleRemoveField,fieldIdx,startEditingField,fieldheader) {
const [open, setOpen] = useState(false);
const currentlyEditing = editIdx === i;
return (
<React.Fragment key={`tr-${i}`}>
<TableRow key={`tr-${i}`}>
{header.map((y, k) => (
<TableCell key={`trc-${k}`}>
{currentlyEditing ? (
<TextField
name={y.prop}
onChange={e => handleChange(e, y.prop, i)}
value={x[y.prop]}
/>
) : (
x[y.prop]
)}
</TableCell>
))}
<TableCell>
{currentlyEditing ? (
<CheckIcon onClick={() => stopEditing()} />
) : (
<EditIcon onClick={() => startEditing(i)} />
)}
<DeleteIcon onClick={() => handleRemove(i)} />
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)} >
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box margin={1}>
<Typography variant="h6" gutterBottom component="div">
Fields
</Typography>
<Table size="small" aria-label="purchases">
<TableHead>
<TableRow>
{fieldheader.map((x, i) => (
<TableCell key={`thc-${i}`}>{x.name} </TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{x.fields.map((fieldRow,y) => (
<TableRow key={`tr-${y}`}>
<TableCell>{fieldRow.bitname}</TableCell>
<TableCell>{fieldRow.bitmask}</TableCell>
<TableCell >{fieldRow.bitvalue}</TableCell>
<TableCell >{fieldRow.maskname}</TableCell>
<TableCell > {fieldRow.doc} </TableCell>
<TableCell >
<DeleteIcon onClick={() => handleRemoveField(i,fieldRow.bitname,y)} /> </TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
); };
If call count of TablerowsAdd varies, the call count of useState varies too.
Try using a component: <TablerowsAdd/> instead of method call: TablerowsAdd(). This way useState is called exactly once per component

Resources