Table Filter with DatePicker using antd - reactjs

Following is the code for Ant design table with filtering the object using the DatePicker but not able to filter Out and Reset and Filter button also not Working Can anyone help me to solve this problem.
CodeSandbox editor Link : https://codesandbox.io/s/customized-filter-panel-antd-4-18-4-forked-lzuru?file=/index.js
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table, DatePicker, Button, Space } from "antd";
import Highlighter from "react-highlight-words";
import { SearchOutlined } from "#ant-design/icons";
const data = [
{
key: "1",
name: "John Brown",
date: "2022-01-27T00:00:00Z",
address: "New York No. 1 Lake Park"
},
{
key: "2",
name: "Joe Black",
date: "2022-01-27T00:00:00Z",
address: "London No. 1 Lake Park"
},
{
key: "3",
name: "Jim Green",
date: "2022-01-25T00:00:00Z",
address: "Sidney No. 1 Lake Park"
},
{
key: "4",
name: "Jim Red",
age: "2022-01-22T00:00:00Z",
address: "London No. 2 Lake Park"
}
];
class App extends React.Component {
state = {
searchText: "",
searchedColumn: ""
};
getColumnSearchProps = (dataIndex) => ({
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters
}) => (
<div style={{ padding: 8 }}>
<Space>
<DatePicker
// format={"DD-MM-YY"}
onChange={(e) => {
setSelectedKeys([e.format("YYYY-MM-DDT00:00:00Z")]);
}}
allowClear={false}
/>
</Space>
<Space>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
{/* <Button
onClick={() => this.handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button> */}
<Button
type="link"
size="small"
onClick={() => {
confirm({ closeDropdown: false });
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex
});
}}
>
Filter
</Button>
</Space>
</div>
),
filterIcon: (filtered) => (
<SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
),
onFilter: (value, record) =>{
return(
record[dataIndex]
? record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase())
: ""
)
},
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
// setTimeout(() => this.searchInput.select(), 100);
}
},
render: (text) =>
this.state.searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: "#ffc069", padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text ? text.toString() : ""}
/>
) : (
text
)
});
handleSearch = (selectedKeys, confirm, dataIndex) => {
console.log(selectedKeys, confirm, dataIndex);
confirm();
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex
});
};
handleReset = (clearFilters) => {
clearFilters();
// console.log(this.state.searchText);
this.setState({ searchText: "" });
};
render() {
console.log(this.state.searchText);
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
width: "30%"
},
{
title: "Date",
dataIndex: "date",
key: "date",
width: "20%",
...this.getColumnSearchProps("date")
}
];
return <Table columns={columns} dataSource={data} />;
}
}

You can use moment to compare the dates and filter
getColumnSearchProps = (dataIndex) => ({
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters
}) => (
<div style={{ padding: 8 }}>
<Space>
<DatePicker
// format={"DD-MM-YY"}
onChange={(e) => {
setSelectedKeys([e]);
}}
allowClear={true}
/>
</Space>
<Space>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => this.handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
<Button
type="link"
size="small"
onClick={() => {
confirm({ closeDropdown: false });
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex
});
}}
>
Filter
</Button>
</Space>
</div>
),
filterIcon: (filtered) => (
<SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
),
onFilter: (value, record) => {
return (
moment(record[dataIndex]).format("DD-MM-YYYY") ===
value.format("DD-MM-YYYY")
);
},

First of all it is a bad idea to compare your dates as strings. or your use case where you only want to compare dates without time, you can compare dates using isSame().
To reset the filter state, you can use a controlled state to clear your filters as shown in the antd clear filter example

Related

ANTD Table filter Control didn't moves with scroll,need to avoid this

I using antd table. I used filtering for a column. Its works perfectly, the issue is in its css. When we scroll down or up the filter field also go up or down with scroll. I want to stay the field with table.
const columns1 = [
{
title: 'Summary',
dataIndex: 'Summary',
key: 'Summary',
// width:100,
sorter: (a, b) => (a.Summary|| '').localeCompare(b.Summary|| ''),
render: (val) => <div title={val} className="text_overlap">{val}</div>,
title: <span>Summary</span>,
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<input
ref={node => {
this.searchInput = node;
}}
placeholder={'Search Action Summary'}
value={selectedKeys[0] || ''}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<button
onClick={() => this.handleSearch(selectedKeys, confirm)}
style={{ width: 90, marginRight: 8 }}
>
Search
</button>
<button
onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</button>
</div>
),
onFilter: (value, record) =>
record.priority
.toString()
.toLowerCase()
.includes(this.state.searchText.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
}]
This is the column code.
<Table scroll={{ y: 'calc(100vh - 650px)' }}
onRow={(record, index) => {
return {
onClick: event => { this.setState({ selectedActionSum: record }) },
};
}}
rowSelection={{ selectedRowKeys: this.state.selectedActionSumRowKeys, onChange: (e) => { this.setState({ selectedActionSumRowKeys: e }) } }}
rowClassName={(record, index) => record === this.state.selectedActionSum ? 'SelectedRow' : ''}
pagination={false}
columns={columns1}
dataSource={datas} />

How to triger a filter on a antd table with searchParams

I am using an antd table with a customized filter and I am trying to implement a new feature using URL search params to save time when sharing filtered results with colleagues, the idea is to share links.
The search params are being set on the URL after a filter, also I created a conditional in componentDidMount to check and get the search params and set the keyword on the in the component's state which I believe is what is required to trigger the filter on the table.
When pasting the URL on a new tab/browser, the component mounts with the desire state value but the filter doesn't kicks in.
Does anyone knows how to do it ? Any help is appreciated
Demo_In_CodeSandbox_here - takes a minute to load the table
I pasted the code below too.
import React from "react";
import "antd/dist/antd.css";
import "./styles.css";
import { Table, Input, Button, Space } from "antd";
import Highlighter from "react-highlight-words";
import { SearchOutlined } from "#ant-design/icons";
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park"
},
{
key: "2",
name: "Joe Black",
age: 42,
address: "London No. 1 Lake Park"
},
{
key: "3",
name: "Jim Green",
age: 32,
address: "Sidney No. 1 Lake Park"
},
{
key: "4",
name: "Jim Red",
age: 32,
address: "London No. 2 Lake Park"
}
];
class App extends React.Component {
state = {
searchText: "",
searchedColumn: ""
};
getColumnSearchProps = (dataIndex) => ({
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters
}) => (
<div style={{ padding: 8 }}>
<Input
ref={(node) => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={(e) =>
setSelectedKeys(e.target.value ? [e.target.value] : [])
}
onPressEnter={() =>
this.handleSearch(selectedKeys, confirm, dataIndex)
}
style={{ marginBottom: 8, display: "block" }}
/>
<Space>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => this.handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
<Button
type="link"
size="small"
onClick={() => {
confirm({ closeDropdown: false });
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex
});
}}
>
Filter
</Button>
</Space>
</div>
),
filterIcon: (filtered) => (
<SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
),
onFilter: (value, record) =>
record[dataIndex]
? record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase())
: "",
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => this.searchInput.select(), 100);
}
},
render: (text) =>
this.state.searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: "#ffc069", padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text ? text.toString() : ""}
/>
) : (
text
)
});
handleSearch = (selectedKeys, confirm, dataIndex) => {
const params = new URLSearchParams(window.location.search);
params.set(dataIndex, selectedKeys[0]);
window.history.replaceState(
{},
"",
`${window.location.pathname}?${params}`
);
confirm();
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex
});
};
handleReset = (clearFilters) => {
clearFilters();
this.setState({ searchText: "" });
};
componentDidMount() {
if (window.location.search) {
let arrParams = null;
const getUrl = new URL(window.location.href);
let params = new URLSearchParams(getUrl.search);
for (let p of params) {
arrParams = p;
}
console.log(arrParams);
const [dataIndex, selectedKeys] = arrParams;
this.setState({
searchText: selectedKeys,
searchedColumn: dataIndex
});
}
}
render() {
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
width: "30%",
...this.getColumnSearchProps("name")
},
{
title: "Age",
dataIndex: "age",
key: "age",
width: "20%",
...this.getColumnSearchProps("age")
},
{
title: "Address",
dataIndex: "address",
key: "address",
...this.getColumnSearchProps("address"),
sorter: (a, b) => a.address.length - b.address.length,
sortDirections: ["descend", "ascend"]
}
];
return <Table columns={columns} dataSource={data} />;
}
}
export default App;

How to use Ant Design DatePicker inside Ant Design Editable Table?

I'm using Ant Design Editable Table where there is an operation column where there is an edit button. I have 2 other columns which are date and value. So what I want to have is when I press on the edit button for a specific row, I want to be able to change the date using <DatePicker /> component from Ant Design. I have not been able to find a solution anywhere online for me. What I have right now is:
EditableTable.js
import React, { useState } from "react";
import { Table, Form, Button, DatePicker } from "antd";
import EditableCell from "./EditableCell";
const OtherLocsTable = ({ data, setData }) => {
const [form] = Form.useForm();
const [editingKey, setEditingKey] = useState("");
const isEditing = (record) => record.key === editingKey;
const edit = (record) => {
form.setFieldsValue({
date: "",
measurement: "",
...record,
});
setEditingKey(record.key);
};
const save = async (key) => {
try {
const row = await form.validateFields();
const newData = [...data];
const index = newData.findIndex((item) => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setData(newData);
setEditingKey("");
} else {
newData.push(row);
setData(newData);
setEditingKey("");
}
} catch (errInfo) {
console.log("Validate Failed:", errInfo);
}
};
const columns = [
{
title: "Date",
dataIndex: "date",
key: "date",
editable: true,
},
{
title: "Measurement",
dataIndex: "measurement",
key: "measurement",
editable: true,
},
{
title: "Operation",
dataIndex: "operation",
render: (_, record) => {
const editable = isEditing(record);
const lastElement = [...data].pop();
return editable ? (
<span>
<a
href="javascript:;"
onClick={() => save(record.key)}
style={{
marginRight: 8,
}}
>
Save
</a>
<Popconfirm title="Sure to cancel?" onConfirm={cancel}>
<a>Cancel</a>
</Popconfirm>
</span>
) : (
<>
<Typography.Link
disabled={editingKey !== ""}
onClick={() => edit(record)}
>
Edit
</Typography.Link>
{data.length > 1 ? (
record.key === lastElement.key ? (
<Typography.Link
type="danger"
disabled={editingKey !== ""}
onClick={() => deleteRow(record)}
style={{
marginLeft: 15,
}}
>
Delete
</Typography.Link>
) : null
) : null}
</>
);
},
},
];
const mergedColumns = columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
inputType:
col.dataIndex === loc
? "number"
: col.dataIndex === "date"
? "date"
: "text",
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
}),
};
});
return (
<>
<Popconfirm title="Confirm save changes?" onConfirm={handleSubmit}>
<Button
key="submit"
style={{
marginBottom: "1em",
width: "100%",
backgroundColor: "green",
}}
>
Save Changes
</Button>
</Popconfirm>
<Form form={form} component={false}>
<Table
components={{
body: {
cell: EditableCell,
},
}}
bordered
dataSource={data}
columns={mergedColumns}
rowClassName="editable-row"
pagination={{
onChange: cancel,
}}
rowKey="date"
/>
</Form>
</>
);
};
}
EditableCell.j
import React from "react";
import { Form, Input, InputNumber, DatePicker } from "antd";
import moment from "moment";
const EditableCell = ({
editing,
dataIndex,
title,
inputType,
record,
index,
children,
...restProps
}) => {
const inputNode =
inputType === "number" ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `Please Input ${title}!`,
},
]}
>
<InputNumber formatter={(value) => value} parser={(value) => value} />
</Form.Item>
) : inputType === "date" ? (
<FormItem
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `Please Input ${title}!`,
},
]}
initialValue={moment(record[dataIndex])}
>
<DatePicker />
</FormItem>
) : (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `Please Input ${title}!`,
},
]}
>
<Input />
</Form.Item>
);
return <td {...restProps}>{editing ? inputNode : children}</td>;
};
export default EditableCell;
UPDATE
Currently with the code I have, I'm getting an error where it says date.clone is not a function
I found a solution
EditableTable.js
import React, { useState } from "react";
import { Table, Form, Button, DatePicker } from "antd";
import moment from 'moment';
import EditableCell from "./EditableCell";
const OtherLocsTable = ({ data, setData }) => {
const [form] = Form.useForm();
const [editingKey, setEditingKey] = useState("");
const isEditing = (record) => record.key === editingKey;
const edit = (record) => {
const {date, measurement} = record;
form.setFieldsValue({
date: (date) ? moment(date) : "",
measurement: measurement || ""
});
setEditingKey(record.key);
};
const save = async (key) => {
try {
const row = await form.validateFields();
const newData = [...data];
const index = newData.findIndex((item) => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setData(newData);
setEditingKey("");
} else {
newData.push(row);
setData(newData);
setEditingKey("");
}
} catch (errInfo) {
console.log("Validate Failed:", errInfo);
}
};
const columns = [
{
title: "Date",
dataIndex: "date",
key: "date",
editable: true,
},
{
title: "Measurement",
dataIndex: "measurement",
key: "measurement",
editable: true,
},
{
title: "Operation",
dataIndex: "operation",
render: (_, record) => {
const editable = isEditing(record);
const lastElement = [...data].pop();
return editable ? (
<span>
<a
href="javascript:;"
onClick={() => save(record.key)}
style={{
marginRight: 8,
}}
>
Save
</a>
<Popconfirm title="Sure to cancel?" onConfirm={cancel}>
<a>Cancel</a>
</Popconfirm>
</span>
) : (
<>
<Typography.Link
disabled={editingKey !== ""}
onClick={() => edit(record)}
>
Edit
</Typography.Link>
{data.length > 1 ? (
record.key === lastElement.key ? (
<Typography.Link
type="danger"
disabled={editingKey !== ""}
onClick={() => deleteRow(record)}
style={{
marginLeft: 15,
}}
>
Delete
</Typography.Link>
) : null
) : null}
</>
);
},
},
];
const mergedColumns = columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
inputType:
col.dataIndex === loc
? "number"
: col.dataIndex === "date"
? "date"
: "text",
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
}),
};
});
return (
<>
<Popconfirm title="Confirm save changes?" onConfirm={handleSubmit}>
<Button
key="submit"
style={{
marginBottom: "1em",
width: "100%",
backgroundColor: "green",
}}
>
Save Changes
</Button>
</Popconfirm>
<Form form={form} component={false}>
<Table
components={{
body: {
cell: EditableCell,
},
}}
bordered
dataSource={data}
columns={mergedColumns}
rowClassName="editable-row"
pagination={{
onChange: cancel,
}}
rowKey="date"
/>
</Form>
</>
);
};
}
EditableCell.j
import React from "react";
import { Form, Input, InputNumber, DatePicker } from "antd";
import moment from "moment";
const EditableCell = ({
editing,
dataIndex,
title,
inputType,
record,
index,
children,
...restProps
}) => {
const inputNode =
inputType === "number" ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `Please Input ${title}!`,
},
]}
>
<InputNumber formatter={(value) => value} parser={(value) => value} />
</Form.Item>
) : inputType === "date" ? (
<FormItem
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `Please Input ${title}!`,
},
]}
>
<DatePicker formate="DD-MM-YYYY" />
</FormItem>
) : (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `Please Input ${title}!`,
},
]}
>
<Input />
</Form.Item>
);
return <td {...restProps}>{editing ? inputNode : children}</td>;
};
export default EditableCell;

And Design Table TypeScript getColumnSearchProps example

i'm using the following ant component : https://ant.design/components/table/
and i'm really struggling to add the following search option in my table :
here's the table i've created so far :
i'm pretty new to both React and Typescript , since the project is not in js but in typescript i cannot get my code to work properly looking at ant documentation ; i've turned my component to a functional component as i'm gonna be using hooks and added some code to get out most of the compiler errors (type declaration for ts) , still have some syntax errors :
heres my code:
import React, { Component, useState } from 'react';
import {connect} from "react-redux";
// #ts-ignore
import Highlighter from 'react-highlight-words';
//**External Libraries */
//REACT MOSAIC
import {ExpandButton, MosaicWindow, RemoveButton} from "react-mosaic-component";
import {MosaicBranch} from "react-mosaic-component/src/types";
//BLUEPRINTJS
import {InputGroup} from "#blueprintjs/core";
//ANTDESIGN
import { Table , Button ,Tag , Input , Space} from "antd";
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
import {CaretRightOutlined , SearchOutlined} from '#ant-design/icons';
//STYLES
import './styles.css'
//API
import {useGetAllUtenti} from '../../../api/index';
import { Utente } from '../../../api/types';
const UserSummaryWindow: React.FC<any> = (props) => {
//HOOKS STATE FOR TABLE SEARCH
const [searchText , setSearchText] = useState('');
const [searchedColumn , setSearchedColumn] = useState('');
const {path} = props;
const dataSource: Object | any = useGetAllUtenti().data;
const ruoli: any = [
{
text: 'User',
value: 'user',
},
{
text: 'Administrator',
value: 'administrator',
},
{
text: 'NumeroVerde',
value: 'numeroVerde',
},
]
const stati: any = [
{
text: 'Attivo',
value: 1,
},
{
text: 'Non Attivo',
value: 0,
}
]
const columns: any = [
{
title: 'Nome',
dataIndex: 'nome',
key: 'nome',
defaultSortOrder: 'descend',
sorter: (a:any, b:any) => { return a.nome.localeCompare(b.nome)},
},
{
title: 'Cognome',
dataIndex: 'cognome',
key: 'cognome',
sorter: (a:any, b:any) => { return a.cognome.localeCompare(b.cognome)},
},
{
title: 'Ruolo',
dataIndex: 'ruolo',
key: 'ruolo',
filters: ruoli,
onFilter: (value:any, record:any) => record.ruolo.indexOf(value) === 0,
sorter: (a:any, b:any) => { return a.ruolo.localeCompare(b.ruolo)},
render: (text: string) => (
<>
{
<Tag color={renderTagColor(text)}>
{text.toUpperCase()}
</Tag>
}
</>)
},
{
title: 'Gestore',
dataIndex: 'gestore',
key: 'gestore',
sorter: (a:any, b:any) => { return a.gestore.localeCompare(b.gestore)},
},
{
title: 'Username',
dataIndex: 'username',
key: 'username',
sorter: (a:any, b:any) => { return a.username.localeCompare(b.username)},
},
// {
// title: 'Password',
// dataIndex: 'password',
// key: 'password',
// },
// {
// title: 'IDEnte',
// dataIndex: 'idEnte',
// key: 'idEnte',
// },
{
title: 'Tipo',
dataIndex: 'tipo',
key: 'tipo',
sorter: (a:any, b:any) => a.tipo - b.tipo,
},
{
title: 'Stato',
dataIndex: 'stato',
key: 'stato',
filters: stati,
onFilter: (value:any, record:any) => record.stato.indexOf(value) === 0,
sorter: (a:any, b:any) => a.stato - b.stato,
render :(stato: number) => (
<>
{
(stato == 1) ?
(
<Tag color="#00cc00">
Attivo
</Tag>
) :
(
<Tag color="#ff0000">
Non Attivo
</Tag>
)
}
</>)
},
{
title: 'Ultimo aggiornamento password',
dataIndex: 'ultimoAggiornamentoPassword',
key: 'ultimoAggiornamentoPassword',
sorter: (a:any, b:any) => a.ultimoAggiornamentoPassword.localeCompare(b.ultimoAggiornamentoPassword)
},
{
title: '',
dataIndex: 'idUtente',
key: 'idUtente',
render: () => (
//da inserire link per andare al dettaglio / modifica utente
<Button type="primary"><CaretRightOutlined /></Button>
),
},
]
const toolbarControls = React.Children.toArray([
<ExpandButton/>,
<RemoveButton/>
]);
function renderTagColor(text:string): string {
switch(text) {
case 'user':
return 'gold';
case 'administrator':
return 'red';
case 'numeroVerde':
return 'green';
default:
return '';
}
}
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: (text:string) =>
searchText === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[searchText]}
autoEscape
textToHighlight={text.toString()}
/>
) : (
text
),
});
function handleSearch (selectedKeys:any, confirm:any, dataIndex:any) {
confirm();
setSearchText(selectedKeys[0]);
setSearchedColumn(dataIndex);
};
function handleReset (clearFilters:any) {
clearFilters();
setSearchText('');
};
return (
<MosaicWindow<string>
title="Riepilogo Utenti"
path={path}
toolbarControls={toolbarControls}
>
<Table
dataSource={dataSource}
columns={columns}
bordered={true}
//pagination={{ pageSize:3,position: ['bottomCenter'] }}
pagination={{position: ['bottomCenter'] }}
rowKey={'idUtente'}
//stile per righe striped
rowClassName={(record, index) => index % 2 === 0 ? 'table-row-light' : 'table-row-dark'}
/>
</MosaicWindow>
);
};
export default UserSummaryWindow;
The part which is giving me headeache is (need to convert it to typescript [strict option in config file is enabled]):
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: (text:string) =>
searchText === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[searchText]}
autoEscape
textToHighlight={text.toString()}
/>
) : (
text
),
});
I'm not here asking you to correct my code , just wanted to know if anyone could share a typescript implementation of that getColumnSearchProps function , or an example of the table component from ant design with typescript code..
Sorry for such a late reply, i was having the same problem.
I found the solution on a github repo someone made. i really wonder why the antd devs don't support typescript in these days.
anyways, here is the repo.
https://github.com/freewind-demos/typescript-react-antd-table-search-column-demo
Basically All the hardwork of moving the old JS code to typescript is done, although there are some linting errors here and there.
I hope anyone who comes looking for this answer really questions their decision to use antd instead of react-table or material-design.
Same answer as Lav Hinsu, but I'll paste the full code here, just in case that link dies.
import "antd/dist/antd.css";
import React from "react";
import ReactDOM from "react-dom";
import { SearchOutlined } from "#ant-design/icons";
import { Table, Button, Input } from "antd";
import { ColumnType } from "antd/lib/table";
function tableColumnTextFilterConfig<T>(): ColumnType<T> {
const searchInputHolder: { current: Input | null } = { current: null };
return {
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
}) => (
<div style={{ padding: 8 }}>
<Input
ref={(node) => {
searchInputHolder.current = node;
}}
placeholder="Search"
value={selectedKeys[0]}
onChange={(e) =>
setSelectedKeys(e.target.value ? [e.target.value] : [])
}
onPressEnter={() => confirm()}
style={{ width: 188, marginBottom: 8, display: "block" }}
/>
<Button
type="primary"
onClick={() => confirm()}
icon={<SearchOutlined />}
size="small"
style={{ width: 90, marginRight: 8 }}
>
Search
</Button>
<Button size="small" style={{ width: 90 }} onClick={clearFilters}>
Reset
</Button>
</div>
),
filterIcon: (filtered) => (
<SearchOutlined style={{ color: filtered ? "#1890ff" : undefined }} />
),
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => searchInputHolder.current?.select());
}
},
};
}
type Data = {
key: string;
name: string;
};
const data: Data[] = [
{
key: "1",
name: "John Brown",
},
{
key: "2",
name: "Jim Green",
},
{
key: "3",
name: "Joe Black",
},
];
function Hello() {
return (
<div>
<Table
columns={[
{
title: "Name",
dataIndex: "name",
render: (text: string) => text,
...tableColumnTextFilterConfig<Data>(),
onFilter: (value, record) => {
return record.name
.toString()
.toLowerCase()
.includes(value.toString().toLowerCase());
},
},
]}
dataSource={data}
/>
</div>
);
}
ReactDOM.render(<Hello />, document.body);
In short, you can just extract the tableColumnTextFilterConfig function and implement the onFilter property on the desired column.

Filter antd Table With datePicker in react

Following is the code for Ant design table with filtering the object using the input field but i want it to transform it for antd datepicker field instead of input field but not getting how to tranform it.
const data = [
{
key: '1',
date: '2020-04-01',
},
{
key: '2',
date: '2020-04-04',
},
{
key: '3',
date: '2020-04-03',
},
{
key: '4',
date: '2020-04-02',
},
];
class App extends React.Component {
state = {
searchText: '',
searchedColumn: '',
};
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90, marginRight: 8 }}
>
Search
</Button>
<Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</Button>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: text =>
this.state.searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
) : (
text
),
});
handleSearch = (selectedKeys, confirm, dataIndex) => {
confirm();
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex,
});
};
handleReset = clearFilters => {
clearFilters();
this.setState({ searchText: '' });
};
render() {
const columns = [
{
title: 'Date',
dataIndex: 'name',
key: 'name',
width: '30%',
...this.getColumnSearchProps('name'),
},
];
return <Table columns={columns} dataSource={data} />;
}
}
ReactDOM.render(<App />, mountNode);
Following is the code for Ant design table with filtering the object using the input field but i want it to transform it for antd datepicker field instead of input field but not getting how to tranform it.
You can use something like this to display a datePicker instead of a searchInput.
<div style={{ padding, width }}>
<DatePicker.RangePicker
autoFocus={autoFocus}
onChange={handleChange}
placeholder={placeholder}
value={value}
format={format}
style={{ marginBottom: 8 }}
/>
<Button
type="primary"
role="search"
onClick={handleSearch}
style={{ width: btnWidth }}
icon={<SearchOutlined />}
size="small"
>
{label[0]}
</Button>
<Button
role="reset"
style={{ width: btnWidth, marginLeft }}
onClick={handleClear}
size="small"
>
{label[1]}
</Button>
</div>
Old question but hope can help someone in the future!
That code is the one from the table search filter but you should create something like this:
// you need momentjs
import moment from "moment";
// the table data
import data from "../fakeData.js";
class myTable extends Component {
constructor(props) {
super(props);
state = {
data: data,
filteredInfo: null,
searchTimeText: null,
searchedTimeColumn: null,
};
};
clearFilters = () => {
this.setState(
{ filteredInfo: null }
);
};
handleTimeRangeSearch = (selectedKeys, confirm, dataIndex) => {
confirm();
this.setState({
searchTimeText: selectedKeys[0],
searchedTimeColumn: dataIndex,
});
};
handleTimeRangeReset = clearFilters => {
clearFilters();
this.setState({
searchTimeRange: null,
searchTimeRangeColumn: null,
});
};
getColumnTimeProps = dataIndex => ({
filterDropdown: ({setSelectedKeys, selectedKeys, confirm, clearFilters}) => (
<div style={{ padding: 8 }}>
<DatePicker.RangePicker
onChange={e => {
setSelectedKeys(e.length ? [e] : [])
}}
placeholder={["Start", "End"]}
value={selectedKeys[0]}
format="YYYY-MM-DD HH:mm:ss"
/>
<Button
type="primary"
role="search"
onClick={() => {
this.handleTimeRangeSearch(selectedKeys, confirm, dataIndex)
}}
style={{ width: 90, marginRight: 8 }}
icon={<SearchOutlined />}
size="small"
>
Search
</Button>
<Button
role="reset"
style={{ width: 90 }}
onClick={() => this.handleTimeRangeReset(clearFilters)}
size="small"
>
Reset
</Button>
</div>
),
filterIcon: filtered => (
<FieldTimeOutlined type="search" style={{ color: filtered ? "#1890ff" : undefined }} />
),
onFilter: (value, record) => record[dataIndex] ? moment(record[dataIndex]).isBetween(moment(value[0]), moment(value[1])) : "",
render: text => text
});
render() {
let {
data,
filteredInfo
} = this.state;
// table columns config
const columns = [
//...
{
title: 'Date',
dataIndex: 'date',
key: 'date',
sorter: (a, b) => a.date > b.date,
sortOrder: sortedInfo.columnKey === 'date' && sortedInfo.order,
...this.getColumnTimeProps('date'),
filteredValue: filteredInfo.date || null,
},
//...
];
// the table
return (<Table dataSource={data} columns={columns} />)
);
}

Resources