I'm using Ant design table for displaying some data. New data arrives every one second. When user clicks on button, I need to export current table data to XSL.
I'm getting current data in this way:
onChange={(pagination, filter, sorter, currentTable) => this.onTableChange(filter, sorter, currentTable)}.
This thing works and gets me good and filtered data, but when I get new data, I can't get those new data because this function is not triggered while none of the filters or sort settings didn't change. Is there any way to get current table data without dummy changing filter to trigger onChange function?
Title and footer return only current page data.
Code show here
{ <Table
dataSource={this.props.data}
rowKey={(record) => { return record.id}}
columns={this.state.Columns}
pagination={this.state.pageSizeOptions}
rowClassName={(record) => { return
this.getRowClassNames(record) }}
expandedRowKeys={ this.state.expandedRowKeys }
expandedRowRender={record => { return
this.getEventsRows(record) }}
onExpand={(expanded, record) => {
this.onExpandRow(expanded, record.id) }}
expandRowByClick={false}
onChange={(pagination, filter, sorter, currentTable)
=> this.onTableChange(filter, sorter, currentTable)}
/>
}
You can store pagination, sorter and filter data in your component state. Also you can pass these params to your redux state and store there. If you can share your code, i can provide more specific answers.
Below you can find my solution for permanent filter. I was sending filter params to API and get filtered data. If you want to filter it in the component, you can use component lifecycle or render method.
onTableChange(pagination, filter, sorter){
const { params, columns } = this.state;
/** You can do any custom thing you want here. Below i update sort type in my state and pass it to my redux function */
if(sorter.order != null)
params.ordering = (sorter.order === 'descend' ? "-" : "")+ sorter.columnKey.toString();
this.setState({params});
this.props.listUsers(this.state.params);
}
This is because you have taken either columns, datasource varibale as object instead of array.
write
this.state.someVariable=[]
instead of
this.state.someVariable = {}
Related
I have a requirement where for each row of a table(rows are dynamically populated), I have a 'Details' button, which is supposed to pop up a modal upon clicking. How do I maintain a state for each of the rows of this table, so that React knows which row I am clicking, and hence pass the props accordingly to the modal component?
What I tried out was create an array of all false values, with length same as my data's. The plan is to update the boolean for a particular row when the button is clicked. However, I'm unable to execute the same.
Here's what I've tried so far:
let initTableState = new Array(data.length).fill(false)
const [tableState, setTableState] = useState(initTableState)
const detailsShow = (index) => {
setTableState(...tableState, tableState[index] = true)
}
I get the 'data' from DB. In the function detailsShow, I'm trying to somehow get the index of the row, so that I can update the corresponding state in 'tableState'
Also, here's what my code to put in modal component looks like, placed right after the row entries are made:
{tableState[index] && DetailModal}
Here DetailModal is the modal component. Any help in resolving this use case is greatly appreciated!
The tableState is a single array object. You are also spreading the array into the setTableState updater function, the state updater function also takes only a single state value argument or callback function to update state.
You can use a functional state update and map the previous state to the next state, using the mapped index to match and update the specific element's boolean value.
const detailsShow = (index) => {
setTableState(tableState => tableState.map((el, i) => i === index ? true : el))
}
If you don't want to map the previous state and prefer to shallow copy the array first and update the specific index:
const detailsShow = (index) => {
setTableState(tableState => {
const nextTableState = [...tableState];
nextTableState[index] = true;
return nextTableState;
})
}
I want to handle server-side sorting, filtering, and pagination separately in my antd table. So whenever pagination is changed it should not call the sorting and filtering function. similarly for both for sorting and filtering. In the antd documentation for Table, they have used onChange prop which will be called whenever sorting, filtering or pagination is changed. https://ant.design/components/table/#components-table-demo-ajax
To handle pagination alone I've used Pagination's onChange prop. But here when pagination is changed it's calling sorting and filtering function and also when sorting and filtering is changed it calls the pagination function.
I'm not sure how to achieve this functionality. Can anyone please help me with this.
Example antd code for the table
const handlePagination = page => {
//This should be called only when pagination changes
dispatch(PaginateData(page));
};
const handleSortFilter= params=> {
//This should be called only when pagination or sorting is called.
dispatch(SortFilterData(params));
};
<Table
rowSelection={rowSelection}
onChange={handleSortFilter}
rowKey={record => record.id}
columns={columns}
dataSource={data}
loading={tableActionInProgress}
pagination={{
onChange: handlePagination,
pageSize: dataPerPage,
total: CountData
}}
/>
Update
In the the antd table documentation for ajax requests (https://ant.design/components/table/#components-table-demo-ajax) I could see that whenever we change sort or filter it changes the page back to 1. Is there anything I need to change in the code so that whenever filter or sorting is changed it should not set the page parameter to 1.
Why I need to perform this is because when the user changes the filter or sorting in a specific page it should not take him back to the first page instead if I get in which page (page number) the user tried to filter or sort, so that I can send the page number in the request and filter/sort accordingly to the page in the backend and send the response back. Is there any option not to set the page back to 1 if sorting or filtering is applied on the antd table.
For manage filters, sort and pagination in backend you need to use api parameter of table onChange:
<Table
columns={[
//...
]}
rowKey="key"
dataSource={youSource}
onChange={handleChange}
pagination={{
total: totalCount // total count returned from backend
}}
/>
Our handleChange:
const handleChange = (pagination, filters, sorter) => {
const offset = pagination.current * pagination.pageSize - pagination.pageSize;
const limit = pagination.pageSize;
const params = {};
if (sorter.hasOwnProperty("column")) {
params.order = { field: sorter.field, dir: sorter.order };
}
getData(offset, limit, params);
};
Getting data from API:
const getData = (offset, limit, params = false) => {
const queryParams = new URLSearchParams();
queryParams.append("offset", offset);
queryParams.append("limit", limit);
queryParams.append("offset", offset);
if(params && params.order) {
queryParams.append("order", JSON.stringify(params.order));
}
// In this example I use axios to fetch
axios
.get(`https://example.com/you/endpoint/?${queryParams.toString()}`)
.then((response) => {
// get response
console.log("Response: ", response);
})
.catch((err) => {
// Handle error
console.log(err);
});
};
You already decide how fetch data, or if you have possibility to implement backend logic, implement query with params from GET.
I am working for a feature where i have to apply a filter outside the component which is using react-table, but the current page number doesn't get reset after the filter is being applied. The result being fetched (have applied server-side pagination) shows the first page's data.
I have tried to use the callback onFetchData to change the current page number but it does'nt get triggered when the filter from outside the component is applied.
render() {
const { orders, onUpdate } = this.props;
const defaultPageSize = 50;
return (
<div className="admin-report-table">
<ReactTable
data={orders.ordersData}
columns={this.columns}
pages={Math.ceil(orders.count / defaultPageSize)}
defaultPageSize={defaultPageSize}
multiSort={false}
showPageSizeOptions={false}
showPaginationTop
className="-striped -highlight"
noDataText="No orders found. Please check your connection or change your filters."
filterable
manual // informs React Table that you'll be handling sorting and pagination server-side
onFetchData={(state) => {
const { page, pageSize, filtered, sorted } = state;
const adjustedPage = page + 1; // since library page starts from 0
onUpdate({
page: adjustedPage,
filtered,
pageSize,
sorted,
});
}}
/>
</div>
);
}
The Page number should be reset to 1 e.g. current display is Page 2 of 3, after the filter from outside the table is applied, the result is fetched and shown but the Page 2 of 3 doesn't change while the result in the table is of page 1.
Set autoResetPage: false
https://react-table.tanstack.com/docs/api/usePagination#table-options
its gonna avoid rendering all the time.
I had the same issue in my react table, in the solution for that, in the componentWillReceiveProps method I update the page props of the react-table and set it to the "0" when react-table gets new filtered data (Props changed ), its work for me fine, so in your code just set page props as 0 when your table get new data from the parent
componentWillReceiveProps(nextProps: Readonly<IProps>): void {
if (nextProps.properties !== this.props.properties && nextProps.properties.length > 0) {
this.setState({
selectedPageNumber : 0
})
}
}
This issue could be solved by the hacky solution found here: TroyWolf's solution.
And read the whole post there - it may be that your current case is in another comment. If the post will be removed somehow I post it here:
store a reference to the ReactTable's instance. It works to directly update myReactTableInstance.state.page = 0
With similar use cases, I have found its best to use once's own controlled page state for index, as mentioned here:
Check here as mentioned in the docs
It becomes simpler to handle the page reset actions on custom filtering/custom sorting, and trigger accordingly
I am using react table's out of the box pagination and the issue I had was how to extract the current pageIndex from react table. Because every time there was an action on the row of React table, that did not alter the no. of rows, the React table would go back to page 0.
Following worked for me, hacky but works -
On parent component calling React table -
signalTableData is where I have my data for columns and datarows. this could be your data.
const [pageIndex, setPageIndex] = useState(0);
<ReactTable
columns={signalTableData ? signalTableData.headerRow : <div>Loading...</div>}
data={signalTableData.dataRows ? signalTableData.dataRows : <div>Loading...</div>}
sortbyCollumn='originDate'
desc={true}
pageIndex = {pageIndex}
setPageIndex = {setPageIndex}
/>
One React Table js -
function Table({ columns, data, sortbyCollumn, desc, pageIndex, setPageIndex }) {...
and
useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
autoResetPage: false,
initialState: {
pageSize: 5,
pageIndex: pageIndex,
sortBy: [
{
id: sortbyCollumn,
desc: desc
}
] },
},
I am new to React and I stumbled upon react-dropdown-tree-select for a specific need I had allowing users to view data in Tree format for selection in DropDown. But, I want the users to only select 1 value at a time. How can i enforce that?
There is no such property available directly in react-dropdown-tree-select. But you can listen to onChange event and reset the entire data which you have passed in data props with the updated data with only one node selected.
Check the following code.
onChange = (currentNode) => {
// keep reference of default data structure.
const updatedData = this.props.defaultData;
// find node related to currentData in your tree and set checked property
this.setState({data : updatedData });
}
render = () => {
return (
<DropdownTreeSelect
data={this.state.data}
onChange={this.onChange}
/>
);
}
This will basically stop the user from selecting multiple options instead of disabling remainig item you are unselecting the previously selected items.
If you just want one element selected at a time you can use mode="radioSelect"
When useing the Table component in Ant-desigin, i want to get the filterd data in table after executing the filter function on the dataSource, but i cannot find the way to get it. There is a function called onChange which can only get the filter conditions which can not get the filtered data.
I kinda found a way. The props title and footer on the <Table /> component take a function which does provide the filtered data.
<Table
footer={currentPageData => {
console.log(currentPageData); // <-- This is an array of the filtered dataSource.
return null;
}}
/>
Add onChange function to Table(sample code is ts, if you are using js, do a little adjustment. And you can check the debug result: total dataSource size is 54, filtered dataSource size is 40, pagination doesn't impact the result
handleChange = (pagination: any, filters: any, sorter: any, extra: { currentDataSource: Array<any>[] }) => {
console.log('Various parameters', extra.currentDataSource);
this.setState({
filteredInfo: extra['currentDataSource']
});
}
renderTable = (columns: Array<object>, dataSource: Array<any>) => {
return (
<Table
dataSource={dataSource}
columns={columns}
expandedRowRender={(record) => (<Markdown source={record['description']} className="brz-mentor-markdown" />)}
onChange={this.handleChange as any}
/>
)
}
You can easily add onChange attribute inside <Table/>. Create a function with 4 params: pagination, filters, sorter, extra and the data you're looking for is extra.currentDataSource.
onChange={
(pagination, filters, sorter, extra) => {
console.log(extra.currentDataSource)
}
}
One case, the onChange solution can't work.
Set a filter on table, onChange will be called, so you can get the correct count of filtered rows.
Reload the table with data from some kind of ajax calling, and because the fitler is still there, so the data will be filtered. But onChange is not called, so no chance to get the correct count after table reloaded.