Ant Design table pagination inconsistent after changing page and subsequent data change - reactjs

Using antd 4.22.8 with react 18.2.0 (cra). Typescript code ahead
I'm using this code to fetch the data I need to show
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10
});
const [sort, setSort] = useState<SorterResult<FOO>>();
const [searchString, setSearchString] = useState<string>();
const [{ data, loading, error }, refetch] = useAxios<FOO[]>({
url: '/endpoint',
params: { skip: ((pagination.current ?? 0) - 1) * (pagination.pageSize ?? 0), take: pagination.pageSize, sortField: sort?.field, sortDirection: sort?.order, search: searchString }
});
const onTableChange: TableProps<FOO>['onChange'] = (pagination, _filters, sorter) => {
setPagination(pagination);
setSort(sorter as SorterResult<FOO>);
};
and this is how the data is shown
<Input.Search placeholder="Search" allowClear onChange={e => setSearchString(e.target.value)} />
<Table
rowKey={record => record.id}
loading={loading}
columns={[
{
title: 'ICCID',
dataIndex: 'id',
sorter: true
},
{
title: 'Name',
dataIndex: 'name',
sorter: true
}
]}
dataSource={data?.data}
pagination={{ position: ['topRight', 'bottomRight'], total: data?.count ?? 0, ...pagination }}
onChange={onTableChange}
/>
The problem arises with the pagination in this component. Imagine these 2 use case:
You never changed page: I can use the search field to perform some search. Pagination changes correctly reflecting the data that came from the endpoint (different page count, etc...).
I've changed the page: on the first load the endpoint returns quite lot of record and you move to, say, page 4 clicking on the relative button on the paginator component. Then perform a search: data returns correctly but pagination does not reflect changes anymore. Page count is still pre-search, and so is the selected page, but not showing page 4 of the freshly searched dataset, but page 1.
What I'd expect is the pagination component is reset itself after dataset changes, as it does when changing pages or sort

Related

How to delete a specific data based on the given ID on the MUI datagrid using firebase real-time as the database

I want to delete a specific data from the MUI Datagrid. Which each data on the Datagridis specified by an ID that is incremented every time there is a new data on the database through this code:
const [userData, setUserData] = useState([]); // holds the data from the database
<DataGrid
rows={userData.map((user, index) => { // the rows are the data from the database
return { ...user, id: index + 1 }; // add ID each row
})}
columns={userColumns.concat(actionColumn)}
pageSize={5}
rowsPerPageOptions={[5]}
components={{ Toolbar: GridToolbar }}
/>
The columns are separated in an array of objects:
export const userColumns = [
{
field: "id",
headerName: "ID",
width: 100,
},
{
field: "name",
headerName: "Name",
width: 150,
},
{
field: "number",
headerName: "Number",
width: 120,
},
];
This is the actionColumn that concatenates the View, Edit, and Delete button to the userColumns
const actionColumn = [
{
field: "action",
headerName: "Action",
width: 200,
renderCell: (params) => {
return (
<>
<div className="cellAction">
<Link to={"/users/" + params.row.id}>
<button className="viewButton">View</button>
</Link>
<button className="deleteButton" onClick={() => handleDelete(params.row.id)}>
Delete
</button>
<Link to={"/users/" + params.row.id}>
<button className="editButton"> Edit</button>
</Link>
</div>
</>
);
},
},
];
I started to work first on handling the delete function. Because I knew if the delete function would work, then I can get the idea of getting a specific ID for the edit and view. However, my delete function seems not working as expected to delete a specific data on the database and on the datagrid itself.
This is what I've tried on the handleDelete function. I can verify that each data has their own id by logging it out. But, when I log out the userRef that suppose holds the users database attached by its id, it returns an object like this:
const handleDelete = (id) => {
console.log(id); // display the id
if (window.confirm("Are you sure you want to delete this user?")) {
const userRef = ref(db, `/users/${id}`);
console.log(userRef); // supposed to display the specified user
console.log(`/users/${id}`)
remove(userRef) // delete the specified data on database
.then(() => {
setUserData(userData.filter((user) => user.id !== id)); // delete specified data on datagrid
toast.success("User deleted successfully");
})
.catch((error) => {
toast.error(error.message);
});
}
};
Logging out the users/${id} shows users/1. It shows the name of the database and the ID from the specified by the datagrid. But, my users database only have unique ID's generated by the firebase. Although, I assume this would still work as I didn't encounter any problems when using HTML tables. Here's an example of my users database below.
Quite new in react, comments and suggestions are appreciated.
Your assumption here is incorrect:
const userRef = ref(db, `/users/${id}`);
console.log(userRef); // supposed to display the specified user
A reference to a node in the database does not yet contain a snapshot of the data from the database. If you want to get the data, you first have to read it from the database.
That said, you don't need to read the data in order to be able to delete. All you need to delete a node is the exact path to that node. So if your code doesn't delete the node you want to delete, I recommend logging the path and checking of that matches with the path in your database:
console.log(`/users/${id}`);

How to set the enable and disable value to table column switch button in react js

Im using class component in my application.
I want to set the value to the table column button. and i fetch the value from backend
it was an array response. Array values auto mapped by my table column key.
Ex: This was my table column and it was auto mapped by fetch response name. fetch response name
is "description".
{
title: 'Description',
dataIndex: 'description',
key: 'description',
sorter: true
},
But problem is how auto mapped to the response name to switch button I try but I can't.
My Switch column:-
{
title: 'Action',
dataIndex: 'enabled',
key: 'enabled',
render: (text: any, record: any) => (
<div>
<Tooltip title="Enable / Disable" color={'#d31145'}>
<Switch autoFocus checkedChildren="Enable" unCheckedChildren="Disable" className={'customswitch'} onChange={checked => this.changeSwitch(checked,record.proId)}/>
</Tooltip>
</div>
),
}
I need to know how to set the fetch value to switch button in react class component.
I fetch All data from using this code.
fetch = (params: any = {}) => {
let providerConfigureDto: ProviderConfigureDto = {...this.state.providerConfigureDto};
this.setState({isLoading: true});
providerConfigureService.getAllProviders(providerConfigureDto).then(res => {
console.log(res.data.content)
const pagination: any = {...this.state.pagination};
pagination.total = res.data.total;
this.setState({
isLoading: false,
total: res.data.totalElements,
providerConfigures: res.data.content,
providerConfigureDto: providerConfigureDto,
pagination
});
})
providerConfigureDto.page = 0
};
ProviderConfigureDto has only sorter option and pagble option only.
I fetch from array from back end and i create a array in state. then i set the array to table datasouce
Like this :-
providerConfigures:Array<any>,
That's all please help me for that.

Update state of a react component when language is changed

I have created a custom table component I forked from ant design. I reuse it in all my components, It takes an array of all columns and renders it. I pass columns as a prop called initialColumns.
My issue is whenever the user changes the language, the table contents is re rendering but not the columns which I passed, they don't get translated, How would I force a rerender when the language is changed.
custom table component
const TableComponent = (props) => {
const { initialColumns, dataSource, handleClick } = props
return ( <Table
columns={colmenu.visibleColumns}
dataSource={dataSource}
size="small"
pagination={{
pageSizeOptions: ['10', '20', '50'],
showSizeChanger: true,
}}
/>)
}
Parent component, here I call my TableComponent as pass it columns
It looks something like this:
const columns = [
{
title: t.status,
dataIndex: 'status',
key: 'status',
sorter: (a, b) => a.status.localeCompare(b.status),
...GetColumnSearchProps(['status']),
className: 'text-center',
checked: true,
},
.
.
.
.
here is how I get the translated files
const { messages: t } = useIntl()
and this is the render method:
<TableComponent
initialColumns={columns}
dataSource={data}
handleClick={addModal}
title="AABC"
/>
So how would I update the initialColumns prop when the language is changed?

componentDidUpdate is one step behind the actual value in the setState

I'm using React and chartJs to create some basic charts for a dashboard.
I want to implement a onClick functionality which will take the clicked element's data and update it in a AgGrid table.
I managed to do that but it appears that I have one problem: Whenever I click one element, it updates the values from the previous clicked element.
I understand that it has to do with the fact that setState is async and does not update at the moment when I click an element.
Any ideas?
below is my code:
handleChartClick = (element) => {
if (element[0] !== undefined) {
const { datasets } = element[0]._chart.tooltip._data;
const datasetIndex = element[0]._datasetIndex;
const dataIndex = element[0]._index;
const dataLabel = element[datasetIndex]._chart.data.labels[dataIndex];
const value = datasets[datasetIndex].data[dataIndex];
//alert(`${dataLabel}: ${value}`);
this.setState({
tabledata: {
columnDefs: [{ headerName: 'Service name', field: 'service', sortable: true, filter: true, resizable: true },
{ headerName: 'Running times', field: 'times', sortable: true, filter: true, resizable: true }],
rowData: [{ service: dataLabel, times: value }]
}
}, () => {});
}
}
In the Child class:
componentDidUpdate() {
this.state.tabledata = this.props.tabledata;
}
Extra: I am using classes for the definition of chart Components and the App.
/// Later Edit:
Found the problem, when i was instantiating my AgGrid, instead of using this.props.smth, I was using the this.state.smth (the problem was that at the current point, the state has not been modified yet and it was referencing to old values).

Delete particular item in React Table?

Header: "Delete",
id:'delete',
accessor: str => "delete",
Cell: (row)=> (
<span onClick={(row) => this.onRemoveHandler(row,props)} style={{cursor:'pointer',color:'blue',textDecoration:'underline'}}>
Delete
</span>
)
React Table
This is related to the header delete span link.The code snippets shows the render the delete label with hyperlink.
Here once a user click on delete link how can I get the id of that particular row.
ID has been already assgined to all the row from the json data.
So,How to pass the cellInfo or rowInfo inside the onClick function .
If you check out the docs (specificaly under 'Renderers'), the row object the cell receives is in the following format:
{
// Row-level props
row: Object, // the materialized row of data
original: , // the original row of data
index: '', // the index of the row in the original array
viewIndex: '', // the index of the row relative to the current view
level: '', // the nesting level of this row
nestingPath: '', // the nesting path of this row
aggregated: '', // true if this row's values were aggregated
groupedByPivot: '', // true if this row was produced by a pivot
subRows: '', // any sub rows defined by the `subRowKey` prop
// Cells-level props
isExpanded: '', // true if this row is expanded
value: '', // the materialized value of this cell
resized: '', // the resize information for this cell's column
show: '', // true if the column is visible
width: '', // the resolved width of this cell
maxWidth: '', // the resolved maxWidth of this cell
tdProps: '', // the resolved tdProps from `getTdProps` for this cell
columnProps: '', // the resolved column props from 'getProps' for this cell's column
classes: '', // the resolved array of classes for this cell
styles: '' // the resolved styles for this cell
}
Depending on what your input data looks like, you can use this information to delete from the dataset. If you plan on dynamically editing your data, you should store it in the state, so that the table component can update according to your edits. Assuming that in your state, you save your dataset as data, and use that to populate the table, you can alter the state in your onclick function:
Header: "Delete",
id:'delete',
accessor: str => "delete",
Cell: (row)=> (
<span onClick={() => {
let data = this.state.data;
console.log(this.state.data[row.index]);
data.splice(row.index, 1)
this.setState({data})
}}>
Delete
</span>
)
so a rough approximation of your app would like this:
this.state = {
data: <your data set>
}
<ReactTable
data={this.state.data}
columns={[
<other columns you have>,
{
Header: "Delete",
id:'delete',
accessor: str => "delete",
Cell: (row)=> (
<span style={{cursor:'pointer',color:'blue',textDecoration:'underline'}}
onClick={() => {
let data = this.state.data;
console.log(this.state.data[row.index]);
data.splice(row.index, 1)
this.setState({data})
}}>
Delete
</span>
)}
]}
/>
And of course, you don't need to log that row to the console, that doesn't need to be there. This is also just the quickest and easiest way to handle it, you could instead use the row object to get any specific element you want (id, name, etc.) and use that to remove from the dataset
An important note though: There is a big difference between viewIndex and index, index is what you want to use for your specific case
If you are like me and are using React-Table v7 and you are also using a hooks based approach in your components you will want to do it this way.
const [data, setData] = useState([]);
const columns = React.useMemo(
() => [
{
Header: 'Header1',
accessor: 'Header1Accessor',
},
{
Header: 'Header2',
accessor: 'Header2Accessor',
},
{
Header: 'Delete',
id: 'delete',
accessor: (str) => 'delete',
Cell: (tableProps) => (
<span style={{cursor:'pointer',color:'blue',textDecoration:'underline'}}
onClick={() => {
// ES6 Syntax use the rvalue if your data is an array.
const dataCopy = [...data];
// It should not matter what you name tableProps. It made the most sense to me.
dataCopy.splice(tableProps.row.index, 1);
setData(dataCopy);
}}>
Delete
</span>
),
},
],
[data],
);
// Name of your table component
<ReactTable
data={data}
columns={columns}
/>
The important part is when you are defining your columns make sure that the data in your parent component state is part of the dependency array in React.useMemo.

Resources