Material ui : Table scroll to top of new page - javascript

I'm a bit lost on this.
I already try many settings with scrollTop.
Let me explain, I'm using material Ui and their pagination stuff with table documentation here
so I'm stuck when I click on next set of row( or change page ), I start at the bottom. but I would like to start at the top of every new row.
If someone can help me and give me an explanation of why, A huge thanks!
sorry, I'm quite new to React.
here is my code :
function DisplayList(props) {
var rows = [];
const data = props.data;
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);
};
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">
{row}
</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>
)
}

Have you tried scrollIntoView?
I used scrollTo not working but scrollIntoView is fine.
const handleChangeRowsPerPage = (event) => {
tableRef.current && tableRef.current.scrollIntoView();
setRowsPerPage(parseInt(event.target.value, 10))
setPage(0)
}

I don't see scrollTop in your example, so it's tough to say exactly what the issue is. If you just trying to scroll the window try window.scrollTo(0, 0);
https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo
If your trying to scroll the table element itself you can use a ref.
To the top of your component add:
function DisplayList(props) {
const tableRef = React.createRef();
var rows = [];
const data = props.data;
...
Add the ref to your table:
return (
<Table
ref={tableRef}
className={classes.table}
aria-label="custom pagination table"
>
<TableBody>
...
Finally your page event use the ref to change scrollTop
const handleChangePage = (event, newPage) => {
setPage(newPage);
tableRef.current?.scrollTop = 0;
};

Оn Angular Material i did like this
// html
<table mat-table [dataSource]="dataSource" #dataTable>
...
</table>
// ts
#ViewChild('dataTable') dataTable: ElementRef;
pageChange(event: { pageSize: number; pageIndex: number; }): void {
const tableElement = this.dataTable['_elementRef']?.nativeElement;
tableElement?.scrollIntoView();
// set current page event.pageIndex or event.pageIndex + 1
// get data
}

Related

Pulling data out of a mapped array to calculate sums in react

I have 2 data sets that are currently being mapped over. the second data set is being mapped over inside of the first data set and rendering the values onto a modal for the user to view. I am however trying to take this second data set that is being mapped over out of its map sequence to render a sum total of each associated data point. For instance, I have a 'goalValue', an 'actualValue', and a 'result' value each of which belong to a specified category.
I should like to grab these data points when they are mapped over and push them out of the map into a separate array and or state to calculate a total that can be rendered at the bottom of the table in the modal itself. I created a separate component called ResultCalculator that takes in each value within the 'category.' Currently the state that i am trying to push the mapped values to is causing an infinite loop. I thought that maybe i could use a 'useEffect' but that isn't possible inside of a callback function.
I have added the code below for reference. Any potential insight would be greatly appreciated. I have been working on this for the last few hours whilst gaining no headway. Any search I've typed in on google has yet to render any valuable response.
Here is the code for the mappings.
const Reports = () => {
// declare const for grabbing user profile
const userProfile = () => {
axios.get('/api/users/profile', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('user')}`
}
}
)
.then(res => {
console.log(res.data)
setUsers({ ...users, months: res.data.months })
})
}
// BUTTON TO DELETE A MONTH
const handleDeleteMonth = (id) => {
console.log(id)
axios.delete(`/api/months/${id}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('user')}`
}
}).then(res => {
console.log(res)
userProfile()
})
}
//GRAB THE USER PROFILE
const [users, setUsers] = useState({ months: [] })
useEffect(() => {
userProfile()
}, [])
// defining modal styles
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 1000,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
// defining modal state
const [open, setOpen] = React.useState({});
const handleOpen = monthId => setOpen(prev => ({ ...prev, [monthId]: true }));
const handleClose = monthId => setOpen(prev => ({ ...prev, [monthId]: false }));
//RESULT CALCULATION STATES
const [actualsArray, setActualsArray] = useState(0)
// const [goalsResult, setGoalsResult] = useState(0)
// const [resultsResult, setResultsResult] = useState(0)
return (
<>
<NavBar></NavBar>
<br></br> <br></br>
<h1 style={{ color: "white", textAlign: "center", fontSize: "50px" }}>Budget Summaries</h1>
<br></br> <br></br>
<Container>
<Grid container spacing={2}>
<Grid item xs={0} md={1}>
</Grid>
<Grid item xs={12} md={10}>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 700 }} aria-label="customized table">
<TableHead>
<TableRow>
<StyledTableCell style={{ fontSize: "25px" }}>Month</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{users.months.map(month => (
<StyledTableRow key={month._id}>
<StyledTableCell component="th" scope="row">
<Button onClick={() => handleOpen(month._id)} align="left">{month.name}</Button>
<Button style={{ minWidth: 200 }} align="right" onClick={() => {handleDeleteMonth(month._id)}}>Delete</Button>
<Modal
open={open[month._id]}
onClose={() => handleClose(month._id)}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Typography id="modal-modal-title" variant="h6" component="h2">
<Container>
< Grid container spacing={2} >
<Grid item xs={0} md={1}>
</Grid>
<Grid item xs={12} md={10}>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 700 }} aria-label="customized table">
<TableHead>
<TableRow>
<StyledTableCell style={{ fontSize: "25px" }}>Categories</StyledTableCell>
<StyledTableCell style={{ fontSize: "25px" }} align="right">Spent</StyledTableCell>
<StyledTableCell style={{ fontSize: "25px" }} align="right">Goals</StyledTableCell>
<StyledTableCell style={{ fontSize: "25px" }} align="right">Results</StyledTableCell>
<StyledTableCell style={{ fontSize: "25px" }} align="right"></StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{month.categories.map(category => (
<>
<StyledTableRow key={category.name}>
<StyledTableCell component="th" scope="row">
{category.name}
</StyledTableCell>
<StyledTableCell align="right">{category.actualValue}</StyledTableCell>
<StyledTableCell align="right">{category.goalValue}</StyledTableCell>
<StyledTableCell align="right">{category.result}</StyledTableCell>
<StyledTableCell align="right"></StyledTableCell>
</StyledTableRow>
</>
))}
<StyledTableRow>
<styledTableCell component="th" scope="row">Net</styledTableCell>
<StyledTableCell align="right"><ResultCalculator/></StyledTableCell>
<StyledTableCell align="right"><ResultCalculator/></StyledTableCell>
<StyledTableCell align="right"><ResultCalculator/></StyledTableCell>
<StyledTableCell align="right"></StyledTableCell>
</StyledTableRow>
</TableBody>
</Table>
</TableContainer>
</Grid>
<Grid item xs={0} md={1}>
</Grid>
</Grid >
</Container >
</Typography>
</Box>
</Modal>
</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Grid>
<Grid item xs={0} md={1}>
</Grid>
</Grid>
</Container>
<br></br><br></br>
<hr style={{ color: "white" }}></hr>
<Footer></Footer>
</>
)
}
I also will include the exterior component called ResultCalculator. There are some things that are commented out because I am currently just trying to get 1 value to calculate correctly before trying the other 2.
> function ResultCalculator(actualValue, goalValue, result) {
>
> const [actualsResult, setActualsResult] = useState(0)
// const [goalsResult, setGoalsResult] = useState(0)
// const [resultsResult,setResultsResult] = useState(0)
>
> let actuals = 0
// let goals = 0
// let results = 0
>
> const actualCalculator = (actualValue) => {
> actuals = actuals + actualValue }
>
> // const goalCalculator = (goalValue) => {
// goals = goals + goalValue
// return goals
// }
>
> // const resultCalculator = (result) => {
// results = results + result
// return results
// }
actualCalculator(actualValue)
>
> // goalCalculator()
// resultCalculator()
useEffect(() => {
> setActualsResult(actuals)
}, [])
>
> // setGoalsResult(goals)
// setResultsResult(results)
>
> return (
> <>
> {actualsResult}
> {/* {goalsResult}
> {resultsResult} */}
> </> )
>
> }

How do I map over data from API in a collapsible table?

I don't know if the question captures what I had in my but I will explain below...
I fetched data from API and mapped into a collapsible table. Full details of the data should be embedded in EACH row such that onclick on each row, reveals the full details. Here's the code below
function Encounter() {
const [open2, setOpen2] = useState(false);
const [details, setDetails] = useState([]);
const getDetails = async () => {
try {
const fetch = await Axios.get(
"https://pshs3.herokuapp.com/all/encounter"
);
setDetails(fetch.data.data)
} catch (err) {
console.log(err);
}
};
useEffect(() => {
getDetails();
}, []);
return (
<Wrapper>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
<TableCell/>
<TableCell >
Enrollment ID
</TableCell>
<TableCell >
Encounter
</TableCell>
<TableCell>
Facility Code
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{details.map((detail, idx) => {
return (
<>
<TableRow sx={{ "& > *": { borderBottom: "unset" } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell key={idx}>
{detail.enrollment_id}
</TableCell>
<TableCell key={idx}>
{detail.encounter}
</TableCell>
<TableCell key={idx}>
{detail.faciity_code}
</TableCell>
</TableRow>
<TableRow>
<TableCell
style={{ paddingBottom: 0, paddingTop: 0 }}
colSpan={6}
>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1 }}>
<Typography variant="h6" gutterBottom component="div">
Details
</Typography>
<Tooltip />
</Box>
</Collapse>
</TableCell>
</TableRow>
</>
);
})}
</TableBody>
</Table>
</Wrapper>
);
}
export default Encounter;
The problem I have is how to implement the open and setOpen state to individual row, also the Tooltip component(which is a the full table details from the API) to display full details of each row onclick which should correspond to the selected row in question.
Here are two solutions to the first problem.
1. Create a separate component for each <TableRow />
This component will have its own state and allows you to collapse/expand each row individually.
2. Use a dictionary for the open state
Since you have multiple (dynamic) rows, you can introduce a dictionary for the open state.
const [open, setOpen] = useState({});
For each row, you will use the open[idx] property to determine if the row should be "open"
<Collapse in={open[idx]} timeout="auto" unmountOnExit>
And in the <IconButton /> component, set the state based on the current row state.
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(current => ({ ...current, [idx]: !current[idx] }))}
>
Firstly add a variable in your details object:
const getDetails = async () => {
try {
const fetch = await Axios.get(
"https://pshs3.herokuapp.com/all/encounter"
);
const response = fetch.data.data;
response.map((elem) => elem.open = false)
setDetails(response)
} catch (err) {
console.log(err);
}
};
Then you can change the open variable for each element in details:
<IconButton
aria-label="expand row"
size="small"
onClick={() => detail.open = !detail.open)}
>
You might need to update the state, so change your onClick:
onClick={() => changeOpenStatus(idx))}
and the function:
const changeOpenStatus = (idx) => {
const newDetails = {...details}
newDetails[idx].open = !newDetails[idx].open;
setDetails(newDetails)
}

Material-UI TextField loses focus on every onChange

I am creating the following component:
It will contain an array of objects, where each object is a prescription, with the medicine name from the select and a TextField for the Dosis.
My problem is that the TextField loses focus on every onChange() and is very frustrating because it cannot be edited on a single focus.
This is my component :
const MedicineSelect = ({ medications, setMedications, ...props }) => {
const { medicines } = useMedicines()
const classes = useStyles()
const handleChange = (index, target) => {
// setAge(event.target.value)
const newMedications = cloneDeep(medications)
newMedications[index][target.name] = target.value
setMedications(newMedications)
}
const handleAddMedicine = () => {
const newMedications = cloneDeep(medications)
newMedications.push({ medicine: '', dosis: '', time: '' })
setMedications(newMedications)
}
const handleDeleteMedicine = (index) => {
console.log('DELETE: ', index)
const newMedications = cloneDeep(medications)
newMedications.splice(index, 1)
setMedications(newMedications)
}
return (
<Paper style={{ padding: 5 }}>
<List>
{medications.map((medication, index) => (
<ListItem key={nanoid()} divider alignItems='center'>
<ListItemIcon>
<Tooltip title='Eliminar'>
<IconButton
className={classes.iconButton}
onClick={() => handleDeleteMedicine(index)}
>
<HighlightOffOutlinedIcon />
</IconButton>
</Tooltip>
</ListItemIcon>
<FormControl className={classes.formControl}>
<InputLabel
id={`${index}-select-${medication}-label`}
>
Medicamento
</InputLabel>
<Select
labelId={`${index}-select-${medication}-label`}
id={`${index}-select-${medication}`}
name='medicine'
value={medication.medicine}
onChange={(event) =>
handleChange(index, event.target)
}
>
{medicines.map((medicine) => (
<MenuItem
key={nanoid()}
value={medicine.name}
>
{medicine.name}
</MenuItem>
))}
</Select>
</FormControl>
<TextField
// fullWidth
id={`${index}-text-${medication}`}
label='Dosis'
name='dosis'
onChange={(event) =>
handleChange(index, event.target)
}
value={medication.dosis}
/>
</ListItem>
))}
<Button onClick={handleAddMedicine}>+ agregar</Button>
</List>
</Paper>
)
}
And here is where I set the component:
const [medications, setMedications] = useState([
{ medicine: '', dosis: '', time: '' },
])
...
<Grid item md={12} xs={12}>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls='panel1a-content'
id='panel1a-header'
>
<Typography variant='h4'>
Tratamiento:
</Typography>
</AccordionSummary>
<AccordionDetails>
<Container disableGutters>
<MedicineSelect
medications={medications}
setMedications={setMedications}
/>
</Container>
</AccordionDetails>
</Accordion>
</Grid>
...
Adding and removing objects from the array works perfect. selecting the medicine from the select, also works perfect. the only problem I have is when editing the Dosis TextField, with every character, the focus is lost and I have to click again on the TextField.
Please help me getting this fixed!!!
After searching a lot, finally I found the solution. Actually when using nanoid() to create unique keys, on every state update React re-renders all components and since the id of both the List and the TextField component are regenerated by nanoid on every render, React loses track of the original values, that is why Focus was lost.
What I did was keeping the keys unmuttable:
<ListItem key={`medication-${index}`} divider alignItems='center'>
and
<TextField
key={`dosis-${index}`}
fullWidth
// id={`${index}-dosis-${medication}`}
label='Dosis'
name='dosis'
onChange={(event) =>
handleChange(index, event.target)
}
value={medication.dosis}
/>

Material UI React Table Pagination

I want to inquire about Table Pagination in React UI Material.
Here I am trying to implement all the data from the API.
Some of the data that I have successfully implemented is from the API to the Material UI Table.
Bring up data based on request Rows Per Page
Bring up the data comes from the API that I have.
However when I try to implement Pagination, the Data doesn't appear properly from the API.
Example:
When the Component is rendered for the first time, it will display 5 data from the API. But when I tried to move to the next page, only the response from the API was successful, but not the data that appeared.
Here I divide it into several files:
Index Component
Index Container
File Index Component.
import React, { useState } from 'react'
// * Material UI
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
Grid,
TableContainer,
Table,
TableHead,
TableRow,
TableCell,
TableBody,
TablePagination,
CssBaseline
} from '#material-ui/core'
import {
Add
} from '#material-ui/icons'
// * Core Component
import Layout from '#containers/v2/core/Layout'
import InputCategoryComponent from './Input'
import CardCore from '../../core/shared/Card'
import Controls from '../../core/shared/controls'
import { isEmpty } from '#client/libs/utils'
const columns = [
{ id: 'name', label: 'Name', minWidth: 500 },
{ id: 'Actions', label: 'Action', minWidth: 100 }
]
export default function CategoryComponent ({
page = 0,
rowsPerPage = 5,
rowsPerPageOptions = [5, 10, 15, 20, 25],
startDate = '',
endDate = '',
sortBy = 'created_at',
sortDirection = 'desc',
search = '',
totalCount = 0,
items = [],
fetch = () => {},
createPaymentCategory = () => {},
readPaymentCategory = () => {},
updatePaymentCategory = () => {},
deletePaymentCategory = () => {},
handleRowPerPage = () => {},
handlePagination = () => {}
}) {
const [isTable, setTable] = useState(true)
const [alert, setAlert] = useState(false)
const [hashed, setHashed] = useState('')
const [initialModel, setModel] = useState([])
const emptyRows = rowsPerPage - Math.min(rowsPerPage, totalCount - page * rowsPerPage)
const handleTable = (params) => {
setTable(params)
}
const handleAlertOpen = (payload) => {
setHashed(payload)
setAlert(true)
}
const handleChange = (payload) => {
if (isEmpty(payload)) {
setModel({
name: ''
})
setTable(false)
} else {
readPaymentCategory(payload).then((res) => {
setModel(res.data)
setTable(false)
})
}
}
const handleAlertClose = () => {
setAlert(false)
}
const onFinish = () => {
fetch(
page,
rowsPerPage,
startDate,
endDate,
sortBy,
sortDirection,
search
)
setTable(true)
setModel({
name: ''
})
}
const onDelete = () => {
deletePaymentCategory(hashed).then(() => {
setHashed('')
setAlert(false)
fetch(
page,
rowsPerPage,
startDate,
endDate,
sortBy,
sortDirection,
search
)
})
}
const onRowChange = (e) => {
handleRowPerPage(e.target.value)
fetch(
0,
e.target.value,
startDate,
endDate,
sortBy,
sortDirection,
search
)
}
const onPageChange = (event, newPage) => {
handlePagination(newPage)
fetch(
newPage,
rowsPerPage,
startDate,
endDate,
sortBy,
sortDirection,
search
)
}
return (
<Layout>
<CssBaseline />
{isTable && (
<Grid container>
<Grid item sm={12} md={12} lg={12}>
<CardCore
variant='info'
title='Payment Category'
>
<Grid container>
<Grid item sm={12} md={12} lg={!2}>
<Controls.Button
text='Create'
color='primary'
startIcon={<Add />}
onClick={() => handleChange()}
/>
</Grid>
</Grid>
<Grid container>
<Grid item sm={12} md={12} lg={!2}>
<TableContainer>
<Table stickyHeader aria-label='sticky table'>
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell
key={column.id}
align={column.align}
style={{ minWidth: column.minWidth }}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{items.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => {
return (
<TableRow hover role='checkbox' tabIndex={-1} key={row.name}>
<TableCell>{row.name}</TableCell>
<TableCell align='left'>
<div>
<Controls.Button
text='Edit'
color='inherit'
onClick={() => handleChange(row.hashed_id)}
/>
<Controls.Button
text='Delete'
color='secondary'
onClick={() => handleAlertOpen(row.hashed_id)}
/>
</div>
</TableCell>
</TableRow>
)
})}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={rowsPerPageOptions}
component='div'
count={totalCount}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={onPageChange}
onChangeRowsPerPage={onRowChange}
/>
</Grid>
</Grid>
</CardCore>
</Grid>
</Grid>
)}
<Dialog
open={alert}
onClose={handleAlertClose}
fullWidth
maxWidth='sm'
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
>
<DialogTitle id='alert-dialog-title'>Are you sure want to delete this?</DialogTitle>
<DialogContent>
<DialogContentText id='alert-dialog-description'>
You wont be able to revert this!
</DialogContentText>
</DialogContent>
<DialogActions>
<Controls.Button
text='Disagree'
color='secondary'
onClick={handleAlertClose}
/>
<Controls.Button
text='Agree'
color='primary'
autoFocus
onClick={onDelete}
/>
</DialogActions>
</Dialog>
{!isTable && (
<InputCategoryComponent
controlTable={handleTable}
initialValues={initialModel}
callBack={onFinish}
createData={createPaymentCategory}
updateData={updatePaymentCategory}
/>
)}
</Layout>
)
}
File Index Container.
import React, { Component } from 'react'
import { mapStateToProps, mapActions } from '#client/store'
import { connect } from 'react-redux'
// * Category Component
import CategoryComponent from '#components/v2/Payment/Category/Index'
class PaymentCategoryContainer extends Component {
constructor (props) {
super(props)
this.state = {
page: 0,
rowsPerPage: 5,
rowsPerPageOptions: [5, 10, 15, 20, 25],
startDate: '',
endDate: '',
sortBy: 'created_at',
sortDirection: 'desc',
search: '',
totalCount: 0,
items: []
}
this.fetch = this.fetch.bind(this)
this.handleRow = this.handleRow.bind(this)
this.handlePage = this.handlePage.bind(this)
}
fetch (page, rowsPerPage, startDate, endDate, sortBy, sortDirection, search) {
this.props.fetchPaymentCategory(
page,
rowsPerPage,
startDate,
endDate,
sortBy,
sortDirection,
search
).then((res) => {
if (res?.status === 200) {
this.setState({
items: res?.data.items,
totalCount: res?.data.totalItems
})
} else {
console.log('error')
}
})
}
handleRow (rowsPerPage) {
this.setState({
rowsPerPage: rowsPerPage
})
const { page, startDate, endDate, sortBy, sortDirection, search } = this.state
this.fetch(
page,
rowsPerPage,
startDate,
endDate,
sortBy,
sortDirection,
search
)
}
handlePage (numberOfPage) {
this.setState({
page: numberOfPage
})
const { rowsPerPage, startDate, endDate, sortBy, sortDirection, search } = this.state
this.fetch(
numberOfPage,
rowsPerPage,
startDate,
endDate,
sortBy,
sortDirection,
search
)
}
componentDidMount () {
this.fetch(
this.state.page,
this.state.rowsPerPage,
'',
'',
this.state.sortBy,
this.state.sortDirection,
''
)
}
render () {
return (
<CategoryComponent
{...this.props}
{...this.state}
fetch={this.fetch}
handleRowPerPage={this.handleRow}
handlePagination={this.handlePage}
/>
)
}
}
export default connect(
mapStateToProps('paymentCategory'),
mapActions(
'fetchPaymentCategory',
'changeRowPerPage',
'changePagination',
'createPaymentCategory',
'readPaymentCategory',
'updatePaymentCategory',
'deletePaymentCategory'
)
)(PaymentCategoryContainer)
Response data from API:
items: [] => array. totalItems: 0 => int
Are there any mistakes that I missed? or is there a step that i missed ?.
I am following the examples in this section ui material.
Thank you.
I have found where the mistake I made. I shouldn't need to slice() the data. Because I have a params page query so I just need to map() something like this.
return (
<Layout>
<CssBaseline />
{isTable && (
<Grid container>
<Grid item sm={12} md={12} lg={12}>
<CardCore
variant='info'
title='Payment Category'
>
<Grid container>
<Grid item sm={12} md={12} lg={!2}>
<Controls.Button
text='Create'
color='primary'
startIcon={<Add />}
onClick={() => handleChange()}
/>
</Grid>
</Grid>
<Grid container>
<Grid item sm={12} md={12} lg={!2}>
<TableContainer>
<Table stickyHeader aria-label='sticky table'>
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell
key={column.id}
align={column.align}
style={{ minWidth: column.minWidth }}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{items.map((row) => {
return (
<TableRow hover role='checkbox' tabIndex={-1} key={row.name}>
<TableCell>{row.name}</TableCell>
<TableCell align='left'>
<div>
<Controls.Button
text='Edit'
color='inherit'
onClick={() => handleChange(row.hashed_id)}
/>
<Controls.Button
text='Delete'
color='secondary'
onClick={() => handleAlertOpen(row.hashed_id)}
/>
</div>
</TableCell>
</TableRow>
)
})}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={rowsPerPageOptions}
component='div'
count={totalCount}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={onPageChange}
onChangeRowsPerPage={onRowChange}
/>
</Grid>
</Grid>
</CardCore>
</Grid>
</Grid>
)}
<Dialog
open={alert}
onClose={handleAlertClose}
fullWidth
maxWidth='sm'
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
>
<DialogTitle id='alert-dialog-title'>Are you sure want to delete this?</DialogTitle>
<DialogContent>
<DialogContentText id='alert-dialog-description'>
You wont be able to revert this!
</DialogContentText>
</DialogContent>
<DialogActions>
<Controls.Button
text='Disagree'
color='secondary'
onClick={handleAlertClose}
/>
<Controls.Button
text='Agree'
color='primary'
autoFocus
onClick={onDelete}
/>
</DialogActions>
</Dialog>
{!isTable && (
<InputCategoryComponent
controlTable={handleTable}
initialValues={initialModel}
callBack={onFinish}
createData={createPaymentCategory}
updateData={updatePaymentCategory}
/>
)}
</Layout>
)
}
Hope this helps others.

TypeError: props.pagination is undefined

I am trying to get page data which is coming from redux store and pass this to local state named pagination. This pagination state is further passed to child component. But the Problem is whenever i try to pass redux state to local state i get error undefined. Here data is defined I can console.log the data but it gets delayed that why i might be getting the error. I don't know how to solve this. I am using react functional component.
newOrder.js
const [pagination, setPagination] = React.useState({});
const DataReceived = (state) =>
state.OrderAndShipping.NewOrderList.newOrder._embedded;
const selectedData = useSelector(DataReceived, shallowEqual);
const NewOrder = selectedData ? selectedData.customerOrderResourceList : null;
const pageState = (state) =>
state.OrderAndShipping.NewOrderList.newOrder.page;
const selectPage = useSelector(pageState);
console.log("page", selectPage);
React.useEffect(() => {
const access_token = localStorage.getItem("access_token");
props.getNewOrderList(access_token, "", ""); <-- redux dispatch function
}, []);
React.useEffect(() => {
setPagination(selectPage); <-- Here i am trying to pass redux state to localstate.
}, []);
const mapStateProps = (state) => {
console.log(state);
return {
newOrder: state.OrderAndShipping.NewOrderList.newOrder
? state.OrderAndShipping.NewOrderList.newOrder._embedded
: null,
};
};
const mapDispatchToProps = {
getNewOrderList, <-- Dispatching function
};
Passing
{TableData && TableData.rows && TableData.rows.length > 0 && (
<Table
_handleCheckbox={_handleCheckbox}
_handlePagination={_handlePagination}
_handleUserCheckBox={_handleUserCheckBox}
data={TableData}
pagination={pagination}
/>
)}
Table.js
const emptyRows =
rowsPerPage -
Math.min(
rowsPerPage,
props.data.rows.length - props.pagination.number * rowsPerPage
);
const { number } = props.pagination;
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<EnhancedTableToolbar numSelected={selected.length} data={props.data} />
<div className={classes.tableWrapper}>
<Table
className={classes.table}
aria-labelledby="tableTitle"
size={dense ? "small" : "medium"}
>
{/*//! Table Head Component */}
<EnhancedTableHead
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={props.data.rows.length}
data={props.data}
/>
{/*//! Table Body Component */}
<TableBody>
{stableSort(props.data.rows, getSorting(order, orderBy))
.slice(number * rowsPerPage, number * rowsPerPage + rowsPerPage)
.map((row, index) => {
const isItemSelected = isSelected(row.name);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
onClick={(event) =>
handleClick(event, row.name, row.userId)
}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={props.data.rows.name}
selected={isItemSelected}
>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</div>
{/**
* ===============================================
* PAGINATION
* =============================================
*/}
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={props.data.rows.length}
rowsPerPage={rowsPerPage}
page={props.pagination.number}
backIconButtonProps={{
"aria-label": "Previous Page",
}}
nextIconButtonProps={{
"aria-label": "Next Page",
}}
onChangePage={props._handlePagination}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Paper>
console.log pagination
console.log("page", selectPage);
Table.js
function EnhancedTable(props) {
const [rowsPerPage, setRowsPerPage] = React.useState(10);
//! Select All Checkbox
function handleSelectAllClick(event) {
if (event.target.checked) {
const newSelecteds = props.data.rows.map((n) => n.name);
setSelected(newSelecteds);
return;
}
setSelected([]);
}
//! Handle CheckBox here
function handleClick(event, name, userId) {
const selectedIndex = selected.indexOf(name);
let newSelected = [];
const selectedIdIndex = SelectedId.indexOf(userId);
let newSelectedIndex = [];
console.log(userId);
let userid = [];
userid = userId;
console.log(selectedIndex);
props._handleCheckbox(selectedIdIndex, userid, SelectedId);
function handleChangeDense(event) {
setDense(event.target.checked);
}
const isSelected = (name) => selected.indexOf(name) !== -1;
const emptyRows =
rowsPerPage -
Math.min(
rowsPerPage,
props.data.rows.length - props.pagination.number * rowsPerPage
);
const { number } = props.pagination;
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<EnhancedTableToolbar numSelected={selected.length} data={props.data} />
<div className={classes.tableWrapper}>
<Table
className={classes.table}
aria-labelledby="tableTitle"
size={dense ? "small" : "medium"}
>
<EnhancedTableHead
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={props.data.rows.length}
data={props.data}
/>
{/*//! Table Body Component */}
<TableBody>
{stableSort(props.data.rows, getSorting(order, orderBy))
.slice(number * rowsPerPage, number * rowsPerPage + rowsPerPage)
.map((row, index) => {
const isItemSelected = isSelected(row.name);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
onClick={(event) =>
handleClick(event, row.name, row.userId)
}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={props.data.rows.name}
selected={isItemSelected}
>
<TableCell padding="checkbox">
<Checkbox
checked={isItemSelected}
inputProps={{ "aria-labelledby": labelId }}
/>
</TableCell>
{rowData(row)}
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</div>
{/**
* ===============================================
* PAGINATION
* =============================================
*/}
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={props.data.rows.length}
rowsPerPage={rowsPerPage}
page={props.pagination.number}
backIconButtonProps={{
"aria-label": "Previous Page",
}}
nextIconButtonProps={{
"aria-label": "Next Page",
}}
onChangePage={() => props.handlePagination()}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Paper>
</div>
);
}
const mapStateToProps = (state) => {
return {
checkbox: state.AllUsers.Admin.checkBox,
};
};
export default connect(mapStateToProps, {})(EnhancedTable);
Issue :
As per your console log you are getting selectPage undefined initially, and you also setting up the value only on mount
React.useEffect(() => {
setPagination(selectPage); <-- Here i am trying to pass redux state to localstate.
}, []); // <--- this will executed only on mount
Solution :
I think you should listen for the changes in selectPage and only update If it's available
React.useEffect(() => {
if(selectPage) { // <--- check if available
setPagination(selectPage);
}
}, [selectPage]); // <--- will run useEffect on everychange of `selectPage`

Categories

Resources