TypeError: props.pagination is undefined - javascript

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`

Related

How to make a form for add and edit with Reack-hook-form

I am trying to create a single form able to manage the creation of a product but also to edit it (by passing the values through an object).
The form works perfectly to create a product but how to make it able to edit a product?
I tried to pass my values via "value" or "defaultValue" but it seems to be a problem with the creation of a product (The values are as saved)
The idea of creating a second form with default values passed in doesn't seem right
All this to create a basic CRUD.
Here is my form, I use Material-UI for the form elements, especially for its modal
export default function App() {
// ReactHookForm
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const [Produits, setProduits] = useState([]);
const [openAjout, setOpenAjout] = useState(false);
const [openModif, setOpenModif] = useState({open: false, produit: null});
const [openSuppr, setOpenSuppr] = useState({open: false, produitId: null});
// Load product.
const Chargement = async () => {
const res = await fetch(`${ENDPOINT}/api/produits`);
const data = await res.json();
setProduits(data);
};
// create new product.
const onSubmit = async (data) => {
const re = await axios.post(`${ENDPOINT}/api/produits`, data, {
headers: { 'Content-Type': 'application/json'}
})
setProduits([...Produits, data])
};
// edit product.
const onSubmitUpdate = async (data) => {
console.log('data', data)
// const re = await axios.put(`${ENDPOINT}/api/produits/${data}`, data, {
// headers: { 'Content-Type': 'application/json'}
// })
};
// delete product.
const confirmSuppr = async (data) => {
setOpenSuppr({open: false, produitId: data});
const re = await axios.delete(`${ENDPOINT}/api/produits/${data}`, data, {
headers: { 'Content-Type': 'application/json'}
})
setProduits(prevState => {
prevState.filter(Produits => {
return Produits.pro_id !== data;
})
});
}
// -- Handler open / close Dialogs
// Handlers des Dialogs
const handleAjout = (Bool) => {
setOpenAjout(Bool);
};
const handleModif = (Bool, Produit) => {
setOpenModif({open: Bool, produit: Produit});
};
const handleSuppr = (Bool, ProduitID) => {
setOpenSuppr({open: Bool, produitId: ProduitID});
};
// Rendering
useEffect(() => {
Chargement();
}, []);
return (
<div>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow style={{ background: "#cad2c5" }}>
<TableCell align="center">{"ID"}</TableCell>
<TableCell align="center">{"Nom"}</TableCell>
<TableCell align="center">{"Description"}</TableCell>
<TableCell align="center">{"Instruction"}</TableCell>
<TableCell align="center">{"Prix"}</TableCell>
<TableCell align="center">{"Action"}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Produits?.map((produit) => (
<TableRow key={`PRO_${produit.pro_id}`}>
<TableCell align="center">{produit.pro_id}</TableCell>
<TableCell align="center">{produit.pro_nom}</TableCell>
<TableCell align="center">{produit.pro_description}</TableCell>
<TableCell align="center">{produit.pro_instruction}</TableCell>
<TableCell align="center">{produit.pro_prix}{' €'}</TableCell>
<TableCell align="center">
<Tooltip title="Modifier" placement="top">
<IconButton
style={{
background: "#ffca3a",
color: "white",
borderRadius: "10%",
}}
onClick={() => handleModif(true, produit)}
>
<EditIcon />
</IconButton>
</Tooltip>
<Tooltip title="Supprimer" placement="top">
<IconButton
style={{
background: "#ff595e",
color: "white",
borderRadius: "10%",
}}
onClick={() => handleSuppr(true, produit.pro_id)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Grid>
<Button
variant="contained"
endIcon={<AddIcon />}
onClick={() => handleAjout(true)}
>
{"Ajouter"}
</Button>
{/**
* Dialog add product
*/}
<Dialog open={openAjout} onClose={() => handleAjout(false)}>
<DialogTitle>{"Ajout d'un produit"}</DialogTitle>
<form onSubmit={handleSubmit(onSubmit)}>
<DialogContent>
<TextField
type={"text"}
name="pro_nom"
{...register("pro_nom", { required: true })}
label="Nom"
placeholder="Hamburger"
autoFocus
variant="outlined"
/>
{errors.pro_nom && <span>Champ requis.</span>}
<TextField
type={"text"}
name="pro_description"
{...register("pro_description", { required: true })}
label="Description"
placeholder="Description du produit"
variant="outlined"
/>
{errors.pro_description && <span>Champ requis.</span>}
<TextField
type={"text"}
name="pro_instruction"
{...register("pro_instruction")}
label="Instruction"
placeholder="Instruction particulière"
variant="outlined"
/>
<TextField
type={"number"}
name="pro_prix"
{...register("pro_prix", { required: true, min: 0, valueAsNumber: true })}
label="Prix"
placeholder="Obligatoire"
variant="outlined"
/>
{errors.pro_prix && <span>Champ requis.</span>}
</DialogContent>
<DialogActions>
<Button type="reset">{"Effacer"}</Button>
<Button onClick={() => handleAjout(false)}>{"Fermer"}</Button>
<Button type="submit">{"Confirmer"}</Button>
</DialogActions>
</form>
</Dialog>
There is a usefule function in react-hook-form called reset. It allows you to predefine the values for the form. Click here to see the documentation.
You just need to call it inside the useEffect hook and specify the fields.
But before that you need to specify a state to check if it is an "add" or "edit" action.
const [action, setAction] = useState();
useEffect(() => {
if(action == "edit"){
reset({
pro_description: "pro_description",
pro_instruction: "pro_instruction"
})
}else if(action == "add"){
reset({
pro_description: "",
pro_instruction: ""
})
}
}, [reset, action])

Selection Checkbox in React using Hooks

I have a problem selecting a single checkbox or multiple checkbox in a table in React. I'm using Material-UI. Please see my codesandbox here
CLICK HERE
I wanted to achieve something like this in the picture below:
<TableContainer className={classes.tableContainer}>
<Table>
<TableHead className={classes.tableHead}>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={false}
inputProps={{ "aria-label": "select all desserts" }}
/>
</TableCell>
{head.map((el) => (
<TableCell key={el} align="left">
{el}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{body?.excluded_persons?.map((row, index) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox checked={true} />
</TableCell>
<TableCell align="left">{row.id}</TableCell>
<TableCell align="left">{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
Seems you are just missing local component state to track the checked status of each checkbox, including the checkbox in the table header.
Here is the implementation for the AddedPersons component since it's more interesting because it has more than one row of data.
Create state to hold the selected persons state. Only add the additional local state, no need to duplicate the passed body prop data (this is anti-pattern anyway) nor add any derived state, i.e. is indeterminate or is all selected (also anti-pattern).
const [allSelected, setAllSelected] = React.useState(false);
const [selected, setSelected] = React.useState({});
Create handlers to toggle the states.
const toggleAllSelected = () => setAllSelected((t) => !t);
const toggleSelected = (id) => () => {
setSelected((selected) => ({
...selected,
[id]: !selected[id]
}));
};
Use a useEffect hook to toggle all the selected users when the allSelected state is updated.
React.useEffect(() => {
body.persons?.added_persons &&
setSelected(
body.persons.added_persons.reduce(
(selected, { id }) => ({
...selected,
[id]: allSelected
}),
{}
)
);
}, [allSelected, body]);
Compute the selected person count to determine if all users are selected manually or if it is "indeterminate".
const selectedCount = Object.values(selected).filter(Boolean).length;
const isAllSelected = selectedCount === body?.persons?.added_persons?.length;
const isIndeterminate =
selectedCount && selectedCount !== body?.persons?.added_persons?.length;
Attach all the state and callback handlers.
return (
<>
<TableContainer className={classes.tableContainer}>
<Table>
<TableHead className={classes.tableHead}>
<TableRow>
<TableCell colSpan={4}>{selectedCount} selected</TableCell>
</TableRow>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={allSelected || isAllSelected} // <-- all selected
onChange={toggleAllSelected} // <-- toggle state
indeterminate={isIndeterminate} // <-- some selected
inputProps={{ "aria-label": "select all desserts" }}
/>
</TableCell>
...
</TableRow>
</TableHead>
<TableBody>
{body?.persons?.added_persons?.map((row, index) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox
checked={selected[row.id] || allSelected} // <-- is selected
onChange={toggleSelected(row.id)} // <-- toggle state
/>
</TableCell>
<TableCell align="left">{row.id}</TableCell>
<TableCell align="left">{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
Update
Seems there was a bug in my first implementation that disallowed manually deselecting people while the select all checkbox was checked. The fix is to move the logic in the useEffect into the toggleAllSelected handler and use the onChange event to toggle all the correct states. Also to add a check to toggleSelected to deselect "select all" when any person checkboxes have been deselected.
const [allSelected, setAllSelected] = React.useState(false);
const [selected, setSelected] = React.useState({});
const toggleAllSelected = (e) => {
const { checked } = e.target;
setAllSelected(checked);
body?.persons?.added_persons &&
setSelected(
body.persons.added_persons.reduce(
(selected, { id }) => ({
...selected,
[id]: checked
}),
{}
)
);
};
const toggleSelected = (id) => (e) => {
if (!e.target.checked) {
setAllSelected(false);
}
setSelected((selected) => ({
...selected,
[id]: !selected[id]
}));
};
Note: Since both AddedPersons and ExcludedPersons components are basically the same component, i.e. it's a table with same headers and row rendering and selected state, you should refactor these into a single table component and just pass in the row data that is different. This would make your code more DRY.
I have updated your added person table as below,
please note that I am using the component state to update the table state,
const AddedPersons = ({ classes, head, body }) => {
const [addedPersons, setAddedPersons] = useState(
body?.persons?.added_persons.map((person) => ({
...person,
checked: false
}))
);
const [isAllSelected, setAllSelected] = useState(false);
const [isIndeterminate, setIndeterminate] = useState(false);
const onSelectAll = (event) => {
setAllSelected(event.target.checked);
setIndeterminate(false);
setAddedPersons(
addedPersons.map((person) => ({
...person,
checked: event.target.checked
}))
);
};
const onSelect = (event) => {
const index = addedPersons.findIndex(
(person) => person.id === event.target.name
);
// shallow clone
const updatedArray = [...addedPersons];
updatedArray[index].checked = event.target.checked;
setAddedPersons(updatedArray);
// change all select checkbox
if (updatedArray.every((person) => person.checked)) {
setAllSelected(true);
setIndeterminate(false);
} else if (updatedArray.every((person) => !person.checked)) {
setAllSelected(false);
setIndeterminate(false);
} else {
setIndeterminate(true);
}
};
const numSelected = addedPersons.reduce((acc, curr) => {
if (curr.checked) return acc + 1;
return acc;
}, 0);
return (
<>
<Toolbar>
{numSelected > 0 ? (
<Typography color="inherit" variant="subtitle1" component="div">
{numSelected} selected
</Typography>
) : (
<Typography variant="h6" id="tableTitle" component="div">
Added Persons
</Typography>
)}
</Toolbar>
<TableContainer className={classes.tableContainer}>
<Table>
<TableHead className={classes.tableHead}>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={isAllSelected}
inputProps={{ "aria-label": "select all desserts" }}
onChange={onSelectAll}
indeterminate={isIndeterminate}
/>
</TableCell>
{head.map((el) => (
<TableCell key={el} align="left">
{el}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{addedPersons?.map((row, index) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox
checked={row.checked}
onChange={onSelect}
name={row.id}
/>
</TableCell>
<TableCell align="left">{row.id}</TableCell>
<TableCell align="left">{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
};
export default AddedPersons;
Please refer to this for a working example: https://codesandbox.io/s/redux-react-forked-cuy51

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.

Material ui : Table scroll to top of new page

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
}

No horizontal scrolling on resized material-ui table

I am struggling to get this table to behave properly. I have set overflow-x to auto for the table. The table is very similar to the material-ui table from here: https://material-ui.com/demos/tables/
The table will shrink to a certain point and will then simply overflow the edge of the page.
gif of the behavior
Class EnhancedTableHead extends Component {
createSortHandler = property => event => {
this.props.onRequestSort(event, property);
};
render() {
const {
onSelectAllClick,
order,
orderBy,
numSelected,
rowCount
} = this.props;
return (
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
indeterminate={numSelected > 0 && numSelected < rowCount}
checked={numSelected === rowCount}
onChange={onSelectAllClick}
/>
</TableCell>
{columnData.map(column => {
return (
<TableCell
key={column.id}
numeric={column.numeric}
padding={column.disablePadding ? 'none' : 'default'}
sortDirection={orderBy === column.id ? order : false}
>
<Tooltip
title="Sort"
placement={column.numeric ? 'bottom-end' : 'bottom-start'}
enterDelay={300}
>
<TableSortLabel
active={orderBy === column.id}
direction={order}
onClick={this.createSortHandler(column.id)}
>
{column.label}
</TableSortLabel>
</Tooltip>
</TableCell>
);
}, this)}
</TableRow>
</TableHead>
);
}
}
EnhancedTableHead.propTypes = {
numSelected: PropTypes.number.isRequired,
onRequestSort: PropTypes.func.isRequired,
onSelectAllClick: PropTypes.func.isRequired,
order: PropTypes.string.isRequired,
orderBy: PropTypes.string.isRequired,
rowCount: PropTypes.number.isRequired
};
const styles = theme => ({
root: {
width: '100%',
marginTop: theme.spacing.unit * 3
},
table: {
minWidth: 700
},
tableWrapper: {
overflowX: 'auto'
}
});
class Companies extends Component {
constructor(props, context) {
super(props, context);
this.state = {
order: 'asc',
orderBy: 'info',
selected: [],
data:
this.props.accounts.length > 0
? this.props.accounts.sort((a, b) => (a.name < b.name ? -1 : 1))
: [],
page: 0,
rowsPerPage: 3
};
}
render() {
const { classes } = this.props;
const { data, order, orderBy, selected, rowsPerPage, page } = this.state;
const emptyRows =
rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);
return (
<Paper className={classes.root}>
<EnhancedTableToolbar numSelected={selected.length} />
<div className={classes.tableWrapper}>
<Table className={classes.table} aria-labelledby="tableTitle">
<EnhancedTableHead
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={this.handleSelectAllClick}
onRequestSort={this.handleRequestSort}
rowCount={data.length}
/>
<TableBody>
{data
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map(n => {
const isSelected = this.isSelected(n.ref);
return (
<TableRow
hover
onClick={event => this.handleRowClick(event, n.ref)}
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={n.ref}
selected={isSelected}
>
<TableCell padding="checkbox">
<Checkbox
checked={isSelected}
onChange={event => this.handleClick(event, n.ref)}
/>
</TableCell>
<TableCell>
<Avatar
alt={n.name}
src={`//logo.clearbit.com/${n.clearBit}`}
onError={e => {
e.target.src =
'https://doxhze3l6s7v9.cloudfront.net/app/static/img/company-default-img.png';
}}
/>
</TableCell>
<TableCell>{n.name}</TableCell>
<TableCell>{n.owner}</TableCell>
<TableCell numeric>{n.dateCreated}</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</div>
<TablePagination
component="div"
count={data.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'Previous Page'
}}
nextIconButtonProps={{
'aria-label': 'Next Page'
}}
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
/>
</Paper>
);
}
}
Companies.propTypes = {
classes: PropTypes.object.isRequired
};
Any insight into why the table behaves the way it does would be greatly appreciated. Thank you!

Categories

Resources