I'm trying to remove filter options from a table once a filter has been selected. For example, if you filter for X then filter options that don't exist on the current dataset shouldn't be available to be selected from since they won't show any rows.
minimum reproducible example:
import * as React from 'react';
import { Row, Col, Table, TableProps } from 'antd';
import "antd/dist/antd.css";
import { ColumnsType } from 'antd/lib/table';
import { ColumnFilterItem } from 'antd/lib/table/interface';
interface DataType {
key: React.Key;
name: string;
age: number;
address: string;
}
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const App: React.FC = () => {
const [data, setData] = React.useState<DataType[]>();
const columns: ColumnsType<DataType> = [
{
key: 'name',
title: 'Name',
dataIndex: 'name',
filters: dataSource.map(ds => { return {text: ds.name, value: ds.name} as ColumnFilterItem}),
onFilter: (value, record) => record.name.indexOf(value as string) === 0,
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
filters: dataSource.map(ds =>{ return {text: ds.age, value: ds.age} as ColumnFilterItem}),
onFilter: (value, record) => record.age === value
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
const onChange: TableProps<DataType>['onChange'] = (pagination, filters, sorter, extra) => {
// Resets the data to hopefully rebuild table with updated column filters.
// I don't think it works that way though.
setData(extra.currentDataSource);
console.log('Current Data:',extra.currentDataSource);
console.log('params', pagination, filters, sorter, extra);
};
React.useEffect(() => {
setData(dataSource);
}, [data, setData]);
return (
<div style={{margin: '1rem', padding: '1rem'}}>
<Row>
<Col>
<Table dataSource={data} columns={columns} onChange={onChange} />
</Col>
</Row>
</div>
);
}
export default App;
From example above:
I want the highlighted option to be removed from the filter options because the filtered table doesn't have any rows with "42" in them now, just not sure how you go about doing that correctly. I thought you might be able to update the table source so the filter functions populating the options won't show them, but that doesn't seem to trigger a full re-render. What would be a better way to accomplish this?
-- edit --
To be clear, I'm trying to look at what is in the current dataset in the table and remove filters that don't apply to the data. Using the example images above, if none of the records have 42 as an option, then that filter should be removed and only 32 is an available option. The same thing should apply to all filters too, not just a single column.
Ok, so the solution is a bit more complex than my previous attempt. First, you want to filter your data to only the data that has been filtered. Then, using that filtered data, you rebuild your filters
for each column using the filtered data. You still want to use a columns
state. Same demo link, but with revised code. Hope this answers your issue. Apologies for misreading your problem earlier.
const onChange = (pagination, filters, sorter, extra) => {
setColumns(() => {
// 1. filter data
let dataCopy = [...data];
for (const [k, v] of Object.entries(filters)) {
if (v) {
// get onFilter callback of that column
const filterCb = COLUMNS.find((e) => e.dataIndex === k).onFilter;
dataCopy = dataCopy.filter((e) => filterCb(v, e));
}
}
// 2. rebuild columns using only the filtered data
const columns = COLUMNS.map((e) => ({ ...e }));
for (const colConfig of columns) {
if (colConfig.filters) {
const colFilters = [...colConfig.filters];
const newColFilters = [];
// iterate over filtered data to retain only values that
// match the onFilter condition of the current colConfig
for (const record of dataCopy) {
const filterRecord = colFilters.find((e) =>
colConfig.onFilter(e.value, record)
);
// add this filterRecord to newColFilter if not exists already
if (
filterRecord &&
newColFilters.findIndex((e) => e.value === filterRecord.value) ===
-1
) {
newColFilters.push(filterRecord);
}
}
colConfig.filters = newColFilters;
}
}
// return modified columns
return columns;
});
};