Material-iu : Table scroll to Top of new page - reactjs

I'm stuck on this for a few days ...
I don't found the way to be on the top of a new page when you click on next, I always stay at the bottom whatever I do.
I already check on StackOverflow and GitHub, I found this issue which seems to be close: #9186
I supposed using ref and callback is the right way, I already try to implement it. However, I'm always stuck at the having the last element and I can't scrollTop to the one of the page
I based my code on Custom pagination actions which is the table page made by material-iu
Here is an example of my code
function DisplayList(props) {
var rows = [];
const data = props.data;
const tableRef = React.createRef();
const searchData = props.searchData;
const setHoverAddress = props.setHoverAddress;
const classes = useStyles1();
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const handleChangePage = (event, newPage) => {
setPage(newPage);
if(tableRef.current) {tableRef.current.scrollTop = 0;}
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
data.map((result, index) => { // WARNING : slice here which limits the number of results: .slice(0, 5)
const volulme = Math.round(result.volulme);
const volulme2 = Math.round(result.volulme2);
rows.push(
<div id={index}>
<ListItem
alignItems="flex-start"
onMouseEnter={e => {
console.log(index);
}}
>
<Grid container direction="row" spacing={1}>
<Grid item xs={5}>
{/* <Stage width={150} height={150}>
<Layer>
<Shape
sceneFunc={(context, shape) => {
context.beginPath();
context.moveTo(20, 10);
context.lineTo(120, 80);
context.lineTo(120, 140);
context.lineTo(22, 140);
context.closePath();
// (!) Konva specific method, it is very important
context.fillStrokeShape(shape);
}}
fill="#00D2FF"
stroke="black"
strokeWidth={2}
/>
</Layer>
</Stage> */}
</Grid>
<Grid item xs={7}>
<ListItemText
primary={
}
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
display="inline"
color="textPrimary"
>
Solid2 : {volulme2}
</Typography>
</React.Fragment>
}
/>
<ListItemText
secondary={
<React.Fragment>
<Typography
component="span"
variant="body2"
display="inline"
color="textPrimary"
>
Solid : {volulme}
</Typography>
</React.Fragment>
}
/>
<FormControlLabel
control={
<Checkbox icon={<FavoriteBorder />}
checkedIcon={<Favorite />}
color="primary"
onClick={(e) => {
if (e.target.checked) {
addFavourite(parc_id, 1)
} else {
removeFavourite(parc_id, 1)
}
}}
name="checkedH" />
}
label="Enregistrer"
/>
</Grid>
</Grid>
</ListItem>
</div>
)
})
return (
<Table className={classes.table} aria-label="custom pagination table">
<TableBody>
{(rowsPerPage > 0
? rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
: rows
).map((row) => (
<TableRow key={index}>
<TableCell component="th" scope="row">
<div ref={tableRef}>
{row}
</div>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
colSpan={3}
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
SelectProps={{
inputProps: { 'aria-label': 'rows per page' },
native: true,
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
)
}
Thank you for your time and your answer!
Have a nice day

You add a ref to the table and use scrollIntoView in handleChangePage
Working demo
Code snippet
...
const handleChangePage = (event, newPage) => {
ref.current.scrollIntoView(); //scroll to the beginning of the table
// window.scrollTo({ top: 0, behavior: 'smooth' }) //scroll to the top of the page
setPage(newPage);
};
...
<TableContainer ref={ref} component={Paper}>
<Table className={classes.table} aria-label="custom pagination table">
<TableBody>
...

Related

Opening Material UI Modal from a parent within a parent

I have a table with a list of teams; the last column in each row opens up a menu, and I want the menu items to open up a modal or a dialog, depending on the item. I want to keep the table, menu, and modal as separate components. So it looks like this:
Teams.tsx
const testDataTeams = [
{ name: 'Cincinatti Bengals', owner: 'John Person', created: '11/11/11', members: 4 },
{ name: 'Los Angeles Rams', owner: 'John Person', created: '11/11/11', members: 3 },
{ name: 'The A-Team', owner: 'John Person', created: '11/11/11', members: 2 },
]
export default function Teams() {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [openModal, setOpen] = React.useState(null);
const open = Boolean(anchorEl);
const moreOptions = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const clickModal = Boolean(openModal)
const closeModal = () => {
setOpen(null)
};
return (
<TableContainer component={Paper}>
<Table sx={{ display: { xs: 'none', md: 'table', lg: 'table' }, minWidth: 700 }} aria-label="customized table">
<TableHead>
<TableRow>
<StyledTableCell>Name</StyledTableCell>
<StyledTableCell align="right">Owner</StyledTableCell>
<StyledTableCell align="right">Date Created</StyledTableCell>
<StyledTableCell align="right">Members</StyledTableCell>
<StyledTableCell align="right"></StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{testDataTeams.map((item) => (
<StyledTableRow key={item.name}>
<StyledTableCell component="th" scope="row">{item.name}</StyledTableCell>
<StyledTableCell align="right">{item.owner}</StyledTableCell>
<StyledTableCell align="right">{item.created}</StyledTableCell>
<StyledTableCell align="right">{item.members}</StyledTableCell>
<StyledTableCell align="right">
<IconButton
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={moreOptions}>
<MoreIcon />
</IconButton>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<TeamMenu clickModal={clickModal} closeModal={closeModal} />
</Menu>
</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
TeamMenu.tsx
export default function TeamMenu(clickModal, closeModal) {
return (
<div>
<MenuItem>
<ListItemIcon>
<NotificationsIcon fontSize="small" />
</ListItemIcon>
<ListItemText>Notification Settings</ListItemText>
</MenuItem>
<MenuItem onClick={closeModal}>
<ListItemIcon>
<EditIcon fontSize="small" />
</ListItemIcon>
<ListItemText>Edit Team Info</ListItemText>
</MenuItem>
<TeamsModal open={clickModal} handleClose={closeModal} />
<MenuItem>
<ListItemIcon>
<GroupIcon fontSize="small" />
</ListItemIcon>
<ListItemText>Edit Members</ListItemText>
</MenuItem>
<MenuItem>
<ListItemIcon>
<DeleteIcon fontSize="small" />
</ListItemIcon>
<ListItemText>Delete Team</ListItemText>
</MenuItem>
</div>
);
}
TeamsModal.tsx
const TeamsModal = ({ open, handleClose }) => {
return (
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box>
<Typography id="modal-modal-title" variant="h6" component="h2">
Text in a modal
</Typography>
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
</Typography>
</Box>
</Modal>
)
}
export default TeamsModal;
I can get props to pass to the Team Menu, but I'm having trouble getting it down another level, and I'm worried I've made my code too convoluted. What would be the best way to execute this?
You can pass a callback function to the TeamsMenu component like you are doing here, but it doesn't look like you are returning the actual TeamsModal component in the Teams component.
You want to have the TeamsModal in the Teams component like so:
const testDataTeams = [
{ name: 'Cincinatti Bengals', owner: 'John Person', created: '11/11/11', members: 4 },
{ name: 'Los Angeles Rams', owner: 'John Person', created: '11/11/11', members: 3 },
{ name: 'The A-Team', owner: 'John Person', created: '11/11/11', members: 2 },
]
export default function Teams() {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [openModal, setOpen] = React.useState<boolean>(false);
const open = Boolean(anchorEl);
const moreOptions = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const clickModal = () => setOpen(true);
const closeModal = () => setOpen(false);
return (
<>
<TableContainer component={Paper}>
<Table sx={{ display: { xs: 'none', md: 'table', lg: 'table' }, minWidth: 700 }} aria-label="customized table">
<TableHead>
<TableRow>
<StyledTableCell>Name</StyledTableCell>
<StyledTableCell align="right">Owner</StyledTableCell>
<StyledTableCell align="right">Date Created</StyledTableCell>
<StyledTableCell align="right">Members</StyledTableCell>
<StyledTableCell align="right"></StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{testDataTeams.map((item) => (
<StyledTableRow key={item.name}>
<StyledTableCell component="th" scope="row">{item.name}</StyledTableCell>
<StyledTableCell align="right">{item.owner}</StyledTableCell>
<StyledTableCell align="right">{item.created}</StyledTableCell>
<StyledTableCell align="right">{item.members}</StyledTableCell>
<StyledTableCell align="right">
<IconButton
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={moreOptions}>
<MoreIcon />
</IconButton>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<TeamMenu clickModal={clickModal} closeModal={closeModal} />
</Menu>
</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
{openModal && (
<TeamsModal open={openModal} handleClose={() => setOpen(false)} />
)}
</>
);
}
Notice that I defined the state type for open as boolean instead of using null.
This ensures the modal will open when the openModal state is set to true.
Also, if you are using Typescript I recommend you define types for components and props to ensure you aren't making silly mistakes and have that sweet autocomplete capability.

Unable to load the second page after API call in React Collapsible Table (Material UI)

Facing this issue where the React Collapsible Table (Material UI) does not seem to reflect with data from the API after I click the next page button on my react table.
When I load the page initially, it reflects with data from the first page of server side paginated data. (see below)
first-page
When I click on the next page, the table shows up blank.
second-page
Here is the weird bit. When I navigate to the third page, the height of the table area doubles and is still blank.
third-page
Here is the code. In a nutshell, I'm iterating through the column names and column values for the jobs and the runs and displaying that.
function Row(props) {
const { row, rows } = props;
// console.log(rows);
// console.log(Object.keys(row))
const [open, setOpen] = React.useState(false);
return (
<React.Fragment>
<TableRow sx={{ "& > *": { borderBottom: "unset" } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
{Object.values(row).map((colVal, counter) => {
if (typeof colVal != "object") {
// console.log(counter);
// console.log(colVal);
if (counter == 0) {
return (
<TableCell key={counter} component="th" scope="row">
{colVal}
</TableCell>
);
} else {
return (
<TableCell
key={counter}
align="right"
style={{
whiteSpace: "normal",
wordWrap: "break-word",
maxWidth: "150px",
}}
>
{colVal}
</TableCell>
);
}
}
})}
</TableRow>
<TableRow
style={{
backgroundColor: "rgb(0, 127, 97,0.2)",
}}
>
<TableCell
style={{
paddingBottom: 0,
paddingTop: 0,
}}
colSpan={Object.keys(rows[0]).length}
>
<Collapse
in={open}
timeout="auto"
// unmountOnExit
>
<Box
sx={{
margin: 1,
maxHeight: 200,
overflow: "auto",
}}
>
<Typography variant="h6" gutterBottom component="div">
Runs
</Typography>
<Table size="small" aria-label="runs">
<TableHead>
<TableRow>
{Object.keys(rows[0].runs[0]).map(
(runColName, runColNameCounter) => {
if (runColNameCounter) {
// console.log(runColNameCounter);
// console.log(runColName);
if (runColNameCounter == 0) {
return (
<TableCell key={runColNameCounter}>
{runColName}
</TableCell>
);
} else {
return (
<TableCell
key={runColNameCounter}
style={{
whiteSpace: "normal",
wordWrap: "break-word",
}}
align="right"
>
{runColName}
</TableCell>
);
}
}
}
)}
{/* <TableCell>Date</TableCell> */}
{/* <TableCell>Run ID</TableCell> */}
{/* <TableCell align="right">Amount</TableCell> */}
{/* <TableCell align="right">Total price ($)</TableCell> */}
</TableRow>
</TableHead>
<TableBody>
{row.runs.map((runRow) => (
<TableRow
sx={{
borderTop: "2px solid #686868",
// borderBottom: "2px solid black",
}}
key={runRow.run_id}
>
{Object.values(runRow).map((runColVal, runCounter) => {
// console.log(runCounter);
// console.log(runColVal);
if (runCounter == 0) {
return (
<TableCell
key={runCounter}
component="th"
scope="row"
>
{runColVal}
</TableCell>
);
} else {
return (
<TableCell
key={runCounter}
align="right"
style={{
whiteSpace: "normal",
wordWrap: "break-word",
}}
>
{runColVal}
</TableCell>
);
}
})}
</TableRow>
))}
</TableBody>
</Table>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
// Row.propTypes = {
// row: PropTypes.shape({
// calories: PropTypes.number.isRequired,
// carbs: PropTypes.number.isRequired,
// fat: PropTypes.number.isRequired,
// history: PropTypes.arrayOf(
// PropTypes.shape({
// amount: PropTypes.number.isRequired,
// customerId: PropTypes.string.isRequired,
// date: PropTypes.string.isRequired,
// }),
// ).isRequired,
// name: PropTypes.string.isRequired,
// price: PropTypes.number.isRequired,
// protein: PropTypes.number.isRequired,
// }).isRequired,
// };
function TablePaginationActions(props) {
const theme = useTheme();
const { count, page, rowsPerPage, onPageChange } = props;
const handleFirstPageButtonClick = (event) => {
onPageChange(event, 0);
};
const handleBackButtonClick = (event) => {
onPageChange(event, page - 1);
};
const handleNextButtonClick = (event) => {
onPageChange(event, page + 1);
};
const handleLastPageButtonClick = (event) => {
onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
};
return (
<Box sx={{ flexShrink: 0, ml: 2.5 }}>
<IconButton
onClick={handleFirstPageButtonClick}
disabled={page === 0}
aria-label="first page"
>
{theme.direction === "rtl" ? <LastPageIcon /> : <FirstPageIcon />}
</IconButton>
<IconButton
onClick={handleBackButtonClick}
disabled={page === 0}
aria-label="previous page"
>
{theme.direction === "rtl" ? (
<KeyboardArrowRight />
) : (
<KeyboardArrowLeft />
)}
</IconButton>
<IconButton
onClick={handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="next page"
>
{theme.direction === "rtl" ? (
<KeyboardArrowLeft />
) : (
<KeyboardArrowRight />
)}
</IconButton>
<IconButton
onClick={handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="last page"
>
{theme.direction === "rtl" ? <FirstPageIcon /> : <LastPageIcon />}
</IconButton>
</Box>
);
}
TablePaginationActions.propTypes = {
count: PropTypes.number.isRequired,
onPageChange: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
};
export default function CollapsibleTable() {
let params = useParams();
let dispatch = useDispatch();
const [loading, setLoading] = React.useState(false);
// const allJobss = useSelector((state) => console.log(state));
const allJobsStatus = useSelector((state) => state.jobs.status);
const rows = useSelector((state) => state.jobs.jobs);
// const [success, setSuccess] = React.useState(false);
const kpiId = params.id;
const fromDateStr = window.sessionStorage.getItem("fromDate");
const toDateStr = window.sessionStorage.getItem("toDate");
var totalEntries = useSelector((state) => state.jobs.totalEntries);
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(5);
// Avoid a layout jump when reaching the last page with empty rows.
const emptyRows =
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0;
const getJobsDispatch = (pageNum = 1) => {
if (!loading) {
// setSuccess(false);
console.log("loading");
setLoading(true);
dispatch(getJobs({ kpiId, fromDateStr, toDateStr, pageNum })).then(
(action) => {
try {
setLoading(false);
console.log("stop loading");
// setRows(action.payload.resp.allJobs);
} catch (e) {
console.log(e);
}
}
);
// console.log(allJobs);
// setRows(allJobs);
}
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
var pageNum = newPage + 1;
getJobsDispatch(pageNum);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
useEffect(() => {
getJobsDispatch();
return () => {
// console.log(allJobs);
};
}, []);
return (
<TableContainer component={Paper}>
{loading && (
<CircularProgress
size={68}
sx={{
// color: green[500],
position: "absolute",
top: "50%",
left: "50%",
zIndex: 1,
}}
/>
)}
<Table aria-label="collapsible table">
<TableHead>
<TableRow>
<TableCell />
{Object.keys(rows[0]).map((colName, colNameCounter) => {
// console.log(rows);
if (typeof rows[0][colName] != "object") {
// console.log(colNameCounter);
// console.log(colName);
if (colNameCounter == 0) {
return <TableCell key={colNameCounter}>{colName}</TableCell>;
} else {
return (
<TableCell
key={colNameCounter}
style={{
whiteSpace: "normal",
wordWrap: "break-word",
maxWidth: "150px",
}}
align="right"
>
{colName}
</TableCell>
);
}
}
})}
</TableRow>
</TableHead>
<TableBody>
{(rowsPerPage > 0
? rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
: rows
).map((row) => (
<Row key={row.name} row={row} rows={rows} />
))}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[]}
colSpan={3}
count={parseInt(totalEntries)}
rowsPerPage={5}
page={page}
SelectProps={{
inputProps: {
"aria-label": "rows per page",
},
native: true,
}}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
);
}

Nested Table on Click of the arrow

I have a table which has arrow on each row. When the arrow is clicked, the row is expected to expand and show more data in a tabular form. When the arrow is clicked again, the expanded nested table should collapse. The code is in typescript.
This is what I have so far. I have created the first table and able to display the data.I am not able to find the right way to display the second nested table.
const columns = [
"First Name",
"Last Name",
];
const [openRows, setOpenRows] = useState<Record<string, boolean>>({});
const toggleRow = (dataRow: any) =>
setOpenRows((prevState) => ({
...prevState,
[dataRow.userId]: true,
}));
return (
<Paper elevation={3} variant="outlined">
<TableContainer className={classes.container}>
<Table stickyHeader classes={{ root: classes.tableRoot }}>
<colgroup>
<col width="5%" />
<col width="10%" />
<col width="15%" />
</colgroup>
<TableHead>
<TableRow>
{columns.map((column, idx) => (
<TableCell
key={column}
className={classes.cell}
role="columnheader"
colSpan={idx === 0 ? 2 : 1}
>
<Typography variant="h6">{column}</Typography>
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{data.map((dataRow) => (
<TableRow
key={dataRow.userId}
title="tableRow"
className={classes.tableRow}
classes={{ hover: classes.hover }}
hover
>
<TableCell classes={{ root: classes.arrowCell }}>
<IconButton
size="small"
onClick={() => toggleRow(dataRow.userId)}
>
{openRows ? <ArrowDropDownIcon /> : <ArrowDropUpIcon />}
</IconButton>
<Collapse
in={openRows[dataRow.userId] ?? false}
timeout="auto"
unmountOnExit
>
<Box margin={1}>
<TableCell>{dataRow.jobDetails.company}</TableCell>
<TableCell>{dataRow.jobDetails.title}</TableCell>
</Box>
</Collapse>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
);
};
export interface UserData {
userId: string;
firstName: string;
lastName: string;
jobDetails: {
company: string;
title: string;
};
}
interface UserDataProps {
data: UserData[];
}
Thank you so much.

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

How to set up data transfer between components?

I need to transfer filterArray data to component TableGenerator from the component Content. They are both child components of App.js
I have tried to transfer data from component Content.js to component TableGenerator.js, they are both child components of App.js. You can see what I did here:
class App extends Component {
updateData = (value) => {
this.setState({filterArray: value})
}
render() {
return (
<div className="App">
<Header/>
<br></br>
<Content updateData={this.updateData}/>
<br></br>
<TableGenerator data={this.state.filterArray}/>
</div>
);
}
function TableGenerator() {
const allUsers = [
{пользователь: "Александра"},
{пользователь: "Шура"},
{пользователь: "Настя"},
{пользователь: "Ира"},
{пользователь: "Ваня"},
{пользователь: "Жора"},
{пользователь: "Гриша"}
];
return (
<Paper style={{maxWidth: 936, marginLeft: '250px'}}>
<Table>
<TableHead>
<TableRow>
{Object.keys(allUsers[0]).map((TableRow, i) => (
<TableCell key={i} align="center">{TableRow.split("_").join(" ")}</TableCell>
))}
</TableRow>
</TableHead>
<p>Props: {this.props.filterArray}</p>
<TableBody>
{allUsers.map((user, i) => (
<TableRow key={i}>
{Object.values(user).map((v, j) => (
<TableCell key={j} align="center">{v}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</Paper>
);
class Content extends React.Component {
constructor(props) {
super(props);
// initial state
this.state = {
textInput: '',
filterArray: []
}
}
clear = () => {
// return the state to initial
this.setState({
textInput: ''
})
}
parseInput = () => {
let tempArray = this.state.textInput.split(" ");// `convert string into array`
this.state.filterArray = tempArray.filter(word => word.endsWith('*'));
}
render() {
return (
<Paper style={{maxWidth: 936, marginLeft: '250px', overflow: 'hidden'}}>
<AppBar position="static" color="default" elevation={0}>
<Toolbar>
<Grid container spacing={16} alignItems="center">
<Grid item xs>
<TextField
fullWidth
placeholder="Введите фразу которую нужно обучить"
id='textInput'
InputProps={{
disableUnderline: true,
}}
value={this.state.textInput}
onChange={(e) => {
this.setState({textInput: e.target.value})
}}
/>
</Grid>
<Grid item>
<Button
variant="contained"
color="primary"
style={{background: 'linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)'}}
onClick={this.parseInput()}
>
Обучить
</Button>
<Button
variant="contained"
color="primary"
style={{background: 'linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)'}}
onClick={() => {
this.props.updateData(this.state.filterArray)
}}
>
Генерировать
</Button>
<Tooltip title="Сбросить">
<IconButton>
<RefreshIcon color="inherit" style={{display: 'block'}} id='clearButton'
onClick={this.clear}/>
</IconButton>
</Tooltip>
</Grid>
</Grid>
</Toolbar>
</AppBar>
</Paper>
);
}
Two errors (1) parseInput() in Content.js, update state using setState() (2) Your props name is data in TableGenerator but you are accessing this.props.filterArray, it should be this.props.datai have created a sandbox as per you code. It is passing data from Content.js to TableGenerator.js.
parseInput = () => {
let tempArray = this.state.textInput.split(" "); // `convert string into array`
let filterArray = tempArray.filter(word => word.endsWith("*"));
this.setState({ filterArray });
};

Resources