A component that combines antd's Table and Form to do the search, display, and operating jobs for data.
Free from:
- Handling pagination
- Handling table row selection
- Writing search field form item components
- Writing row actions components
Just focus on:
- Doing the data fetching request and return the data
- Rendering a specific data field if needed
- Writing plugin to operate one or many data object(s)
$ yarn add antd-data-table --save
import { DataTable } from 'antd-data-table'
const searchFields: SearchField[] = [
{
label: 'ID',
name: 'id',
type: 'input',
payload: {
props: {
placeholder: 'placeholder'
}
}
},
{
label: 'Select',
name: 'select',
type: 'select',
payload: {
options: [
{ key: '1', label: 'one', value: '1' },
{ key: '2', label: 'two', value: '2' },
{ key: '3', label: 'three', value: '3' }
]
}
}
]
const columns: TableColumnConfig<any>[] = [
{
key: 'id',
title: 'ID',
dataIndex: 'id'
}, {
key: 'title',
title: 'Title',
dataIndex: 'title'
}
]
const expands: Expand[] = [
{
title: 'Body',
dataIndex: 'body',
render (value) {
return value && `${value.substr(0, 100)} ...`
}
},
{
title: 'User ID',
dataIndex: 'userId'
}
]
const onSearch = async ({ page, pageSize, values }) => {
const res = await axios.get('http://jsonplaceholder.typicode.com/posts', {
params: {
_page: page,
_limit: pageSize,
...values
}
})
return {
dataSource: res.data,
total: Number(res.headers['x-total-count'])
}
}
render(
<DataTable
rowKey={record => record.id}
searchFields={searchFields}
initialColumns={columns}
initialExpands={expands}
onSearch={onSearch}
/>
, mountNode)
Sometimes there are many search fields, you could set a maxVisibleFieldCount
to automatically have a collapsable form:
import { DataTable } from 'antd-data-table'
render(
<DataTable
rowKey={record => record.id}
searchFields={searchFields}
initialColumns={columns}
onSearch={onSearch}
+ maxVisibleFieldCount={4}
/>
, mountNode)
We usually need to write some action buttons for operating a specific record. antd-data-table
made it super easy:
const actions: RowAction[] = [
{
label: 'Edit',
action (record) {
action('onClick edit')(record)
}
},
{
label: 'More',
children: [
{
label: 'Remove',
action (record) {
action('onClick remove')(record)
}
},
{
label: 'Open',
action (record) {
action('onClick open')(record)
}
}
]
}
]
render(
<DataTable
rowKey={record => record.id}
searchFields={searchFields}
initialColumns={columns}
initialExpands={expands}
onSearch={onSearch}
actions={actions}
/>
, mountNode)
Plugins are for operating multiple records. Every plugin will render a component at the top of table.
Let's write a simplest plugin: A button that show current selected rows' ids:
const ShowIdsBtn = ({ selectedRows, clearSelection }) => {
const showIds = () => {
message.info(selectedRows.map(row => row.id).join(','))
// clear selection after the action is done
clearSelection()
}
return <Button onClick={showIds}>Show Ids</Button>
}
const plugins = [
renderer (selectedRowKeys, selectedRows, clearSelection) {
return <ShowIdsBtn selectedRows={selectedRows} clearSelection={clearSelection} />
}
]
render (
<DataTable
rowKey={record => record.id}
searchFields={searchFields}
plugins={plugins}
initialColumns={columns}
initialExpands={expands}
onSearch={onSearch}
/>
, mountNode)
Unique table name.
The key
value of a row.
SearchField is an object that contains:
- label: string Pass to
<Form.Item>
'slabel
property. - name: string Pass to
getFieldDecorator
as the decorator name. - type?: RenderType antd-data-table comes with some common form item type. Such as
input
,select
. - initialValue?: any Inital form value.
- renderer?: (payload?: object) => React.ReactNode When the form item types are not statisfied, your could write your own renderer. the
ReactNode
that returned will be wrapped bygetFieldDecorator
. - validationRule?: ValidateionRule[] antd validation rules. Pass to
getFieldDecorator(name, { rules })
. - payload?: { props: any, [key: string]: any } Some params that pass to the renderer.
- span?: number Form Item Col span value. 6 by default.
interface payload {
props: object // antd Input props
}
interface payload {
props: object // antd DatePicker props
}
interface payload {
props: object // antd TreeSelect props
}
interface payload {
props: object, // antd Select props
options: {
key: string,
label: string,
value: string
}[]
}
antd's TableColumnConfig. See more at https://ant.design/components/form/
type Expand = {
/** Title of this column **/
title: string,
/** Display field of the data record, could be set like a.b.c **/
dataIndex: string,
/** Renderer of the column in the expanded. The return value should be a ReactNode **/
render?: (text: any, record?: {}) => React.ReactNode
}
onSearch
property need a function that return a Promise, which resolves an object that contains total
and dataSource
. This function receive a SearchInfo
:
type SearchInfo = {
/** values from `getFieldsValue()` */
values: any,
/** current page */
page: number,
/** page size */
pageSize: number
}
Error handler that trigger when onSearch throw error.
Load list data immediately, default is false
Form validation failed handler
default is 10
If true
, a list selection button will display on table title.
Be sure to pass the name
props if it is enable.
Custom rowSelection
.
For Affix
. Specifies the scrollable area dom node
Pixels to offset from top when calculating position of scroll
Pixels to offset from bottom when calculating position of scroll
There is a public fetch
method in DataTable to do this action. So you could get it from ref
:
// ...
render () {
let dataTableRef: DataTable | null = null
const saveDataTableRef = (ref: DataTable) => {
dataTableRef = ref
}
const onClickCustomSearch = () => {
if (dataTableRef) {
dataTableRef.fetch(1)
}
}
return (
<div style={{ padding: '1em' }}>
<DataTable
ref={saveDataTableRef}
name='customSearch'
rowKey={record => record.id}
searchFields={searchFields}
initialColumns={columns}
initialExpands={expands}
onSearch={onSearch}
pageSize={10}
onError={onError}
/>
<Button onClick={onClickCustomSearch}>Custom Search</Button>
</div>
)
}
fetch: async (page: number, values: object = this.state.currentValues, clearPagination: boolean = false)
$ yarn
$ yarn start # start the storybook
$ yarn test # run the test
$ yarn run build # build the distribution file
$ yarn run build:storybook # build storybook
$ yarn run build:storybook # build storybook
$ npm publish
MIT License