How to use react-window with React Table version 6.10.0? - reactjs

I am following this virtualized-rows example of react table. I know this code is using react and react table latest versions.
How can I use the react-window package with my react table version 6.10.0 and react version is 16.2.0? Also, I am loading data from backend in blocks, for example, the first 500 records, then the next 500 records and so on but the react table is visible to users with first 500 records and after this data is kept on appending, in this case, react-window FixedSizeList function is useful or VariableSizeList is useful?
Code to render React Table:
const columns = this.renderColumn();
<ReactTable
data={data}
filterable={true}
defaultFilterMethod={(filter, row) =>
matchSorter([row[filter.id]], filter.value).length !== 0
}
columns={columns}
showPagination={false}
pageSize={data.length}
minRows={0}
ref={r => {
this.selectTable = r;
}}
noDataText="No results found"
defaultSorted={[
{
id: 'travelerLastName',
desc: false,
},
]}
/>
Function to render columns:
renderColumn = () => [
{
name: '',
Header: x => {
return (
<div className={s.selectAllWrapper}>
<label className={s.checkboxContainer}>
<input
type="checkbox"
onChange={() => this.toggleSelectAll()}
checked={this.state.selectAll === 1}
ref={input => {
if (input) {
input.indeterminate = this.state.selectAll === 2;
}
}}
/>
<span className={s.checkmark} />
</label>
</div>
);
},
Cell: ({ original }) => {
return (
<div className={s.selectAllWrapper}>
<label className={s.checkboxContainer}>
<input
type="checkbox"
className="checkbox"
checked={this.state.selected[original.id] === true}
onChange={() => this.toggleRow(original.id)}
/>
<span className={s.checkmark} />
</label>
</div>
);
},
Filter: ({ filter, onChange }) => (
<div
style={{
background: 'rgba(155, 155, 155, 0.1)',
padding: '7px 5px',
fontSize: 'inherit',
fontWeight: 'normal',
outline: 'none',
height: '40px',
border: 'none',
}}
>
<SearchIcon title={''} />
</div>
),
sortable: false,
width: 45,
},
{
id: `travelerFirstName`,
Header: 'First Name',
Cell: ({ original }) => {
return (
<a
href={`/client/travelers/${original.traveler_id}?tab=profile`}
target="_blank"
>
{original.travelerFirstName}
</a>
);
},
accessor: d => d.travelerFirstName,
filterMethod: function(filter, rows) {
return filterIncludedData(
rows,
'travelerFirstName',
filter.value.toLowerCase(),
);
},
filterAll: true,
Filter: ({ filter, onChange }) => (
<input
placeholder="Search First Name"
value={filter ? filter.value : ''}
onChange={event => onChange(event.target.value)}
/>
),
className: 'left-aligned',
},
];
Some code snippets will really help.

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} />

Antd Creating Dynamic Form Item inside table

Hello I am trying to achieve this code. where in I am creating new purchase order. I add items to table using its unique barcode. Whenever I add an item. it should also create a dynamic form item field that contains InputNumber. Upon submission all items with desired quantity should be submitted.
I am confused on how should I implement this. Any insights will do. the documentation is kinda limited on this.
Here is how I implemented this but it is not working.
const columns = [
{title: 'ID',dataIndex: 'barcode',sorter: true,width: 'auto'},
{title: 'Product',dataIndex: 'name',sorter: true,width: 'auto'},
{title: 'Brand',dataIndex: 'brand',sorter: true,width: 'auto'},
{title: 'Quantity',dataIndex:'quantity_order',sorter: true,width: 'auto', editable:true,
render:(text,record,index)=>(
<Col>
<Form.Item
name="record.quantity_order"
rules={[{ required: true, message: 'Please input a quantity' }]}
>
<InputNumber/>
</Form.Item>
</Col>
)},
{title: 'Price',dataIndex: 'unit_price',width: 'auto'},
{title: 'Action',width: 'auto',render:(text,record)=>(
<Col>
<span style={{marginRight:"0.5rem"}}>
<Button shape="circle" icon={<EyeOutlined/>} size={'large'} onClick={()=>{}}/>
</span>
<span>
<Button shape="circle" icon={<DeleteOutlined/>} size={'large'} onClick={()=>{}}/>
</span>
</Col>
)}
];
Also tried with the dynamic form implementation. but It cannot be positioned inside column render function.
I use two forms. One for adding barCode and second form, i wrapped around the table. I used immer library for immutable state. You can replace it with any other package or add your own code to update.
import produce from 'immer';
import { Button, Col, Form, Input, InputNumber, Table, TableColumnType } from 'antd';
import { DeleteOutlined, EyeOutlined } from '#ant-design/icons';
import { useState } from 'react';
let index = 1;
export default function App() {
const [form] = Form.useForm();
const [tableForm] = Form.useForm();
const [data, setData] = useState<any[]>([]);
const columns: TableColumnType<any>[] = [
{ title: 'ID', dataIndex: 'barcode', sorter: true, width: 'auto' },
{ title: 'Product', dataIndex: 'name', sorter: true, width: 'auto' },
{ title: 'Brand', dataIndex: 'brand', sorter: true, width: 'auto' },
{
title: 'Quantity',
dataIndex: 'quantity_order',
sorter: true,
width: 'auto',
render: (text, record, index) => (
<Col>
<Form.Item name={['record.quantity_order', index]} rules={[{ required: true, message: 'Please input a quantity' }]}>
<InputNumber
onChange={(e) => {
setData(
produce((draft) => {
draft[index].quantity_order = e;
})
);
}}
/>
</Form.Item>
</Col>
)
},
{ title: 'Price', dataIndex: 'unit_price', width: 'auto' },
{
title: 'Action',
width: 'auto',
render: (text, record) => (
<Col>
<span style={{ marginRight: '0.5rem' }}>
<Button shape='circle' icon={<EyeOutlined />} size={'large'} onClick={() => {}} />
</span>
<span>
<Button shape='circle' icon={<DeleteOutlined />} size={'large'} onClick={() => {}} />
</span>
</Col>
)
}
];
const onFinish = (formData: any) => {
let barcode = data.find((val) => val.barcode === formData.barcode);
if (!barcode) {
setData(
produce((draft) => {
draft.push({
barcode: formData.barcode,
name: `Product Name ${index}`,
brand: `Brand ${index}`,
quantity_order: 0,
unit_price: 0
});
})
);
index++;
}
form.resetFields();
};
const onSubmit = () => {
tableForm.validateFields().then(() => {
console.log('Data:', data);
});
};
return (
<>
<Form form={form} onFinish={onFinish}>
<Form.Item name='barcode' rules={[{ required: true }]}>
<Input
addonAfter={
<Button type='primary' htmlType='submit'>
Add
</Button>
}
/>
</Form.Item>
</Form>
<Form form={tableForm} onFinish={onSubmit}>
<Table dataSource={data} columns={columns} />
<Button htmlType='submit'>Submit</Button>
</Form>
</>
);
}

Unexpected useState behaviour in ant design table

I have ant design form and table side by side,When I fill the form data and click on add entity button the data should be displayed in the table. Now the data does get rendered when I click on add entity but again when I fill the form and click on the add entity button the previous data gets disappeared, Now I know that I need to copy the previous data and I did that too but its not working.
My Problem:- The previous form state value which is rendered in the table gets disappeared when new form data is added
My query:- How and Where should I copy the previous object with the spread operator so that it does not get reset.
My code is
import { Card, Table } from "antd";
import { Form, Input, Button, Select, Space, AutoComplete } from "antd";
import { DeleteOutlined, PlusOutlined, SendOutlined } from "#ant-design/icons";
import { useState } from "react";
const ExampleComponent = (props) => {
// Destructuring props
const { intent_data, entity_data } = props;
const [dataSource, setDataSource] = useState([{}]);
// To handle the disable state of Select Entity Select DropDown
const [addentity,setAddEntity] = useState(false)
// Handler function passed to YES/NO Select Option
const addEntityHandler = (addEntity) => {
if(addEntity === 'no'){
setAddEntity(true)
}else{
setAddEntity(false)
}
}
const [form] = Form.useForm();
const onFinish = (values) => {
console.log(values);
form.resetFields();
const dataArr = [];
// Push values to array since dataSource takes array not an object
dataArr.push(values);
setDataSource(dataArr);
};
const columns = [
{
title: "Entity",
dataIndex: "entity_name",
key: "entity_name",
},
{
title: "Entity Value",
dataIndex: "entity_value",
key: "entity_value",
},
{
title: "Operation",
key: "operation",
render: (record: any) => (
<DeleteOutlined
style={{ color: "red" }}
onClick={() => console.log(record)}
/>
),
},
];
return (
<Card className="csi-project-card-0934">
<div className="example-layout">
<div style={{ flexBasis: "100%" }}>
<Form
form={form}
labelCol={{ span: 7 }}
wrapperCol={{ span: 10 }}
layout="horizontal"
colon={true}
onFinish={onFinish}
size="large"
>
{/* <h4>Create Example</h4> */}
<Form.Item
label="Select Intent"
name="intent_name"
className="csi-ant-form-item"
rules={[{ required: true, message: "Intent Cannot be Empty!" }]}
>
<Select>
{/* {intent_data?.map?.((value) => (
<Select.Option
key={value.intent_ID}
value={value.intent_name}
>
{value.intent_name}
</Select.Option>
))} */}
<Select.Option value="intent demo">Intent Demo</Select.Option>
<Select.Option value="intent test">Intent Test</Select.Option>
</Select>
</Form.Item>
<Form.Item
label="Enter Example"
name="example_name"
className="csi-ant-form-item"
hasFeedback
rules={[
{ required: true, message: "This Field Cannot be Empty!" },
({ getFieldValue }) => ({
validator(_, value) {
if (value.length < 4) {
return Promise.reject("Length too short");
}
return Promise.resolve();
},
}),
]}
>
<AutoComplete>
<Input allowClear/>
</AutoComplete>
</Form.Item>
<Form.Item
label="Do you want to add Entity"
name="add_entity"
className="csi-ant-form-item"
rules={[{ required: true, message: "This Cannot be Empty!" }]}
>
<Select placeholder="SELECT" onSelect={(addEntity) => addEntityHandler(addEntity)}>
<Select.Option value="yes">YES</Select.Option>
<Select.Option value="no">NO</Select.Option>
</Select>
</Form.Item>
<Form.Item
label="Select Entity"
name="entity_name"
className="csi-ant-form-item"
>
<Select disabled = {addentity}>
<Select.Option value="entity demo">Entity Demo</Select.Option>
<Select.Option value="entity test">Entity Test</Select.Option>
</Select>
</Form.Item>
<Form.Item
label="Select Value"
name="entity_value"
className="csi-ant-form-item"
hasFeedback
rules={[
{ required: true, message: "This Field Cannot be Empty!" },
]}
>
<AutoComplete>
<Input placeholder="Select Value from Example" />
</AutoComplete>
</Form.Item>
<Form.Item className="csi-ant-form-item">
<Button
key="submit"
type="primary"
htmlType="submit"
shape="round"
>
Add Entity <PlusOutlined />
</Button>
</Form.Item>
</Form>
</div>
<div
style={{
flexBasis: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Table
bordered
className="ib-table"
dataSource={dataSource}
columns={columns}
pagination={{ pageSize: 6 }}
rowKey={Math.random().toString()}
/>
<Button key="submit" type="primary" htmlType="submit" shape="round">
Submit <SendOutlined />
</Button>
</div>
</div>
</Card>
);
};
export default ExampleComponent;
The form data is stored in values object and the structure of values is
{
add_entity: "yes"
entity_name: "entity demo"
entity_value: "Test"
example_name: "Test"
intent_name: "intent demo"
}
One thing to note here is that dataSource state variable is array of objects, like
[{
add_entity: "yes"
entity_name: "entity demo"
entity_value: "Test"
example_name: "Test"
intent_name: "intent demo"
}]
My Expected Output is Below
Entity
Entity Value
Operation
entity demo
test
delete icon
intent demo
test
delete icon
What if you try with
setDataSource(prevDataSource => [...prevDataSource, values]);
?
In the same way, to delete an item:
{
title: "Operation",
key: "operation",
render: (record) => (
<DeleteOutlined
style={{ color: "red" }}
onClick={() => {
setDataSource(prevDataSource => prevDataSource.filter(item => item.entity_name !== record.entity_name //entity_name or whatever id the item has ))
}}
/>
),
},
By the way, try to avoid using any whenever possible if you're using typescript. Here is how to:
import { Table } from 'antd';
import { ColumnsType } from 'antd/es/table';
interface User {
key: number;
name: string;
}
const columns: ColumnsType<User> = [
{
key: 'name',
title: 'Name',
dataIndex: 'name',
},
];
const data: User[] = [
{
key: 0,
name: 'Jack',
},
];
export default () => (
<>
<Table<User> columns={columns} dataSource={data} />
/* JSX style usage */
<Table<User> dataSource={data}>
<Table.Column<User> key="name" title="Name" dataIndex="name" />
</Table>
</>
);

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