I want to add filter, search to ant design tables. Based on the documentation, we need to add some props to table column but it will be repeatative. Is there a way that we can creat a seperate component for the columns and filtering those columns?
I tried to develop that component but the column props' do not accept JSX.
I've done it in this way:
SearchHighliter:
const HighlighterWrapper = memo(({ searchWords, textToHighlight }) => (
<Highlighter
highlightStyle={{
backgroundColor: '#ffc069',
padding: 0,
}}
searchWords={searchWords}
autoEscape
textToHighlight={textToHighlight}
/>
))
FilterHook:
import { useRef, useState } from 'react'
import { Button, Input, Space } from 'antd'
import { SearchOutlined } from '@ant-design/icons'
const useTableFilter = () => {
const [searchText, setSearchText] = useState('')
const [searchedColumn, setSearchedColumn] = useState('')
const searchInput = useRef(null)
const handleSearch = (selectedKeys, confirm, dataIndex) => {
confirm()
setSearchText(selectedKeys[0])
setSearchedColumn(dataIndex)
}
const handleReset = (clearFilters, confirm) => {
clearFilters()
setSearchText('')
confirm()
}
const getColumnSearchProps = (dataIndex) => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div
style={{
padding: 8,
}}
>
<Input
ref={searchInput}
placeholder="Search text"
value={selectedKeys[0]}
onChange={(e) => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => handleSearch(selectedKeys, confirm, dataIndex)}
style={{
marginBottom: 8,
display: 'block',
}}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{
width: 90,
}}
>
Search
</Button>
<Button
onClick={() => clearFilters && handleReset(clearFilters, confirm)}
size="small"
style={{
width: 90,
}}
>
Reset
</Button>
</Space>
</div>
),
filterIcon: (filtered) => (
<SearchOutlined
style={{
color: filtered ? '#1890ff' : undefined,
marginRight: 10,
}}
/>
),
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => searchInput.current?.select(), 100)
}
},
})
return [searchText, searchedColumn, getColumnSearchProps]
}
export default useTableFilter
Table:
const SummaryReport = () => {
const [data, setData] = useState([])
const [isLoading, setIsLoading] = useState(false)
const [searchText, searchedColumn, getColumnSearchProps] = useTableFilter()
const columns = [
{
title: () => <span style={{ paddingLeft: 8 }}>Name</span>,
key: 'name',
dataIndex: 'name',
className: 'no-padding-cell-report',
width: 250,
...getColumnSearchProps('name'),
onFilter: (value, record) => get(record, 'name').toString().toLowerCase().includes(value.toLowerCase()),
render: (_, record) => (
<div style={{ padding: 8 }}>
{searchedColumn === 'name' ? (
<HighlighterWrapper
searchWords={[searchText]}
textToHighlight={get(record, 'name') ? get(record, 'name').toString() : ''}
/>
) : (
get(record, 'name')
)}
</div>
),
},
]
....
}
All you need is just provide 2 functions to your column:
onFilter
- here you describe your filter logic, if your data object is simple like in my case, the function also is trivialrender
- you need to provide this function if you want to highlight text that the user inputs to filter input.