Skip to content

Comprehensive Usage

Example: simplify operations in a CRUD list.

This version may contain more code, including types, styles, and pagination handling. Adjust as needed in real projects.

With Antd table

Details
tsx
import './index.css'
import {Button, Card, Flex, message, Modal, Pagination, Space, Table, type TableProps, Tag} from "antd";
import {AdDynamicForm, type adDynamicFormRef, renderInput, renderSelect} from "dynamicformdjx-react/antd";
import {useDyForm, useReactiveForm} from "dynamicformdjx-react";
import {useEffect, useMemo, useRef, useState} from "react";

interface RowData {
    key: number
    name: string
    age: number
    address: string
    tags: string[]
}

type PageModal = {
    pageSize: number
    pageNo: number
}
const data: RowData[] = [
    {
        key: 0,
        name: 'John Brown',
        age: 1,
        address: 'New York No. 1 Lake Park',
        tags: ['nice', 'developer']
    },
    {
        key: 1,
        name: 'Jim Green',
        age: 2,
        address: 'London No. 1 Lake Park',
        tags: ['wow']
    },
    {
        key: 2,
        name: 'Joe Black',
        age: 3,
        address: 'Sidney No. 1 Lake Park',
        tags: ['cool', 'teacher']
    },
]
const tagsSelection = ['yarn', 'yell', 'cool', 'teacher', 'wow', 'nice', 'developer'].map(it => ({
    label: it,
    value: it
}))
const ZealBase = () => {
    const [messageApi, contextHolder] = message.useMessage();
    const [searchFormItems] = useReactiveForm<RowData, any>([
        {
            key: "name",
            label: "Name",
            value: null,
            allowClear: true,
            render2: f => renderInput({}, f),
            span: 12
        },
        {
            key: "age",
            label: "Age",
            value: null,
            allowClear: true,
            render2: f => renderInput({}, f),
            span: 12
        },
    ])
    const [handleFormItems, setHandleFormItems] = useReactiveForm<RowData>([
        {
            key: "name",
            label: "Name",
            value: null,
            required: true,
            render2: f => renderInput({}, f),
        },
        {
            key: "age",
            label: "Age",
            value: null,
            allowClear: true,
            render2: f => renderInput({}, f),
        },
        {
            key: "address",
            label: "Address",
            value: null,
            allowClear: true,
            type: 'textarea',
            rows: 2,
            render2: f => renderInput({}, f),
        },
        {
            key: "tags",
            label: "Tags",
            value: [],
            allowClear: true,
            mode: 'multiple',
            render2: f => renderSelect(tagsSelection, {}, f),
        },
    ])
    const useHandleForm = useDyForm([handleFormItems, setHandleFormItems])
    const searchFormItemRef = useRef<adDynamicFormRef<RowData>>(null)
    const handleRef = useRef<adDynamicFormRef<RowData>>(null)
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [tableData, setTableData] = useState<RowData[]>([])
    const [pageModal, setPageModal] = useState<PageModal>({
        pageNo: 1, pageSize: 10
    })
    const [renderId, setRenderId] = useState(-1)
    const pagedData = useMemo(() => {
        const {pageNo, pageSize} = pageModal
        const start = (pageNo - 1) * pageSize
        return tableData.slice(start, start + pageSize)
    }, [pageModal, tableData])
    const columns: TableProps<RowData>['columns'] = [
        {
            title: 'Name',
            dataIndex: 'name',
            key: 'name',
        },
        {
            title: 'Age',
            dataIndex: 'age',
            key: 'age',
        },
        {
            title: 'Address',
            dataIndex: 'address',
            key: 'address',
        },
        {
            title: 'Tags',
            key: 'tags',
            dataIndex: 'tags',
            render: (_, {tags}) => (
                <Flex gap="small" align="center" wrap>
                    {tags.map((tag) =>
                        <Tag color={tag.length > 5 ? 'geekblue' : 'green'} key={tag}>
                            {tag.toUpperCase()}
                        </Tag>
                    )}
                </Flex>
            ),
        },
        {
            title: 'Action',
            key: 'action',
            render: (_, record) => (
                <Space size="small">
                    <Button size='small' color='orange' variant={'dashed'} onClick={() => {
                        setRenderId(record.key)
                        useHandleForm.setValues(record)
                        setIsModalOpen(true)
                    }}>Update</Button>
                    <Button size='small' color='red' variant={'dashed'} onClick={() => {
                        setTableData(p => p.filter(it => it.key !== record.key))
                        messageApi.success('删除成功')
                    }}>Delete</Button>
                </Space>
            ),
        },
    ];
    useEffect(() => {
        setTableData(data);
    }, [])
    return (
        <div className='zeal'>
            {contextHolder}
            <Card title={
                <>
                    <div className='title'>
                        Antd Form Table Test
                    </div>
                    <AdDynamicForm<RowData> ref={searchFormItemRef} items={searchFormItems}
                                            preset='grid'/>
                    <div className='search'>
                        <div className="searchBtn">
                            <Button variant={'dashed'} size='small' onClick={() => {
                                searchFormItemRef.current?.reset?.()
                                setTableData(data)
                                pageModal.pageNo = 1
                            }}>Reset</Button>
                            <Button color={'blue'} variant={'dashed'} size='small' onClick={() => {
                                const params = searchFormItemRef.current?.getResult?.()
                                messageApi.info(JSON.stringify(params, null, 2));
                                setTableData(tableData.filter(it => (!params?.name || it.name.includes(params.name)) && (params?.age == null || it.age === Number(params.age))))
                                pageModal.pageNo = 1
                            }}>Search</Button>
                        </div>
                    </div>
                    <div className="controlBtn">
                        <Button color={'green'} variant={'dashed'} size='small' onClick={() => {
                            setRenderId(-1)
                            useHandleForm.onReset()
                            setIsModalOpen(true)
                        }}>Add</Button>
                    </div>
                </>
            } actions={[
                <div className='footer'>
                    <Pagination total={tableData.length} showSizeChanger pageSize={pageModal.pageSize}
                                current={pageModal.pageNo}
                                showTotal={(total) => `Total ${total}`}
                                onChange={(page, size) => {
                                    setPageModal(prev => ({
                                        pageNo: size !== prev.pageSize ? 1 : page,
                                        pageSize: size,
                                    }))
                                }}
                    />
                </div>
            ]}>
                <Table
                    dataSource={pagedData}
                    columns={columns}
                    pagination={false}
                    style={{}}
                />
            </Card>
            <div className="update">
                <Modal
                    title={(renderId === -1 ? 'Add' : 'Update') + ' item'}
                    open={isModalOpen}
                    onOk={() => {
                        handleRef.current?.validator().then(values => {
                            let msg = ''
                            if (renderId === -1) {
                                setTableData(p => [...p, {...values, key: Date.now()}])
                                msg = '添加成功'
                            } else {
                                setTableData(p => p.map(it => (it.key === renderId ? {...it, ...values} : it)))
                                msg = '修改成功'
                            }
                            messageApi.success(msg)
                            setIsModalOpen(false)
                        }).catch(console.error)
                        /*let msg=''
                        const values=useHandleForm.getValues() as RowData
                        if (renderId===-1) {
                            const d=[...tableData]
                            d.push({...values,key:Date.now(),})
                            setTableData(d)
                            msg='添加成功'
                        }else {
                            setTableData(tableData.map(it=>{
                                if (it.key===renderId) return {...values,key:renderId}
                                return it
                            }))
                            msg='修改成功'
                        }
                        messageApi.success(msg)
                        setIsModalOpen(false)*/
                    }}
                    onCancel={() => {
                        setIsModalOpen(false)
                    }}
                >
                    <AdDynamicForm<RowData> items={handleFormItems} ref={handleRef}/>
                </Modal>
            </div>
        </div>
    )
}
export default ZealBase;
jsx
import './index.css'
import {Button, Card, Flex, message, Modal, Pagination, Space, Table, Tag} from "antd";
import {AdDynamicForm, renderInput, renderSelect} from "dynamicformdjx-react/antd";
import {useDyForm, useReactiveForm} from "dynamicformdjx-react";
import {useEffect, useMemo, useRef, useState} from "react";

const data = [
    {
        key: 0,
        name: 'John Brown',
        age: 1,
        address: 'New York No. 1 Lake Park',
        tags: ['nice', 'developer']
    },
    {
        key: 1,
        name: 'Jim Green',
        age: 2,
        address: 'London No. 1 Lake Park',
        tags: ['wow']
    },
    {
        key: 2,
        name: 'Joe Black',
        age: 3,
        address: 'Sidney No. 1 Lake Park',
        tags: ['cool', 'teacher']
    },
]

const tagsSelection = ['yarn', 'yell', 'cool', 'teacher', 'wow', 'nice', 'developer'].map(it => ({
    label: it,
    value: it
}))

const ZealBase = () => {
    const [messageApi, contextHolder] = message.useMessage();

    const [searchFormItems] = useReactiveForm([
        {
            key: "name",
            label: "Name",
            value: null,
            allowClear: true,
            render2: f => renderInput({}, f),
            span: 12
        },
        {
            key: "age",
            label: "Age",
            value: null,
            allowClear: true,
            render2: f => renderInput({}, f),
            span: 12
        },
    ])

    const [handleFormItems, setHandleFormItems] = useReactiveForm([
        {
            key: "name",
            label: "Name",
            value: null,
            required: true,
            render2: f => renderInput({}, f),
        },
        {
            key: "age",
            label: "Age",
            value: null,
            allowClear: true,
            render2: f => renderInput({}, f),
        },
        {
            key: "address",
            label: "Address",
            value: null,
            allowClear: true,
            type: 'textarea',
            rows: 2,
            render2: f => renderInput({}, f),
        },
        {
            key: "tags",
            label: "Tags",
            value: [],
            allowClear: true,
            mode: 'multiple',
            render2: f => renderSelect(tagsSelection, {}, f),
        },
    ])

    const useHandleForm = useDyForm([handleFormItems, setHandleFormItems])
    const searchFormItemRef = useRef(null)
    const handleRef = useRef(null)
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [tableData, setTableData] = useState([])
    const [pageModal, setPageModal] = useState({
        pageNo: 1, pageSize: 10
    })
    const [renderId, setRenderId] = useState(-1)

    const pagedData = useMemo(() => {
        const {pageNo, pageSize} = pageModal
        const start = (pageNo - 1) * pageSize
        return tableData.slice(start, start + pageSize)
    }, [pageModal, tableData])

    const columns = [
        {
            title: 'Name',
            dataIndex: 'name',
            key: 'name',
        },
        {
            title: 'Age',
            dataIndex: 'age',
            key: 'age',
        },
        {
            title: 'Address',
            dataIndex: 'address',
            key: 'address',
        },
        {
            title: 'Tags',
            key: 'tags',
            dataIndex: 'tags',
            render: (_, {tags}) => (
                <Flex gap="small" align="center" wrap>
                    {tags.map((tag) =>
                        <Tag color={tag.length > 5 ? 'geekblue' : 'green'} key={tag}>
                            {tag.toUpperCase()}
                        </Tag>
                    )}
                </Flex>
            ),
        },
        {
            title: 'Action',
            key: 'action',
            render: (_, record) => (
                <Space size="small">
                    <Button size='small' color='orange' variant={'dashed'} onClick={() => {
                        setRenderId(record.key)
                        useHandleForm.setValues(record)
                        setIsModalOpen(true)
                    }}>Update</Button>
                    <Button size='small' color='red' variant={'dashed'} onClick={() => {
                        setTableData(p => p.filter(it => it.key !== record.key))
                        messageApi.success('删除成功')
                    }}>Delete</Button>
                </Space>
            ),
        },
    ];

    useEffect(() => {
        setTableData(data);
    }, [])

    return (
        <div className='zeal'>
            {contextHolder}
            <Card title={
                <>
                    <div className='title'>
                        Antd Form Table Test
                    </div>
                    <AdDynamicForm ref={searchFormItemRef} items={searchFormItems}
                                   preset='grid'/>
                    <div className='search'>
                        <div className="searchBtn">
                            <Button variant={'dashed'} size='small' onClick={() => {
                                searchFormItemRef.current?.reset?.()
                                setTableData(data)
                                pageModal.pageNo = 1
                            }}>Reset</Button>
                            <Button color={'blue'} variant={'dashed'} size='small' onClick={() => {
                                const params = searchFormItemRef.current?.getResult?.()
                                messageApi.info(JSON.stringify(params, null, 2));
                                setTableData(tableData.filter(it => (!params?.name || it.name.includes(params.name)) && (params?.age == null || it.age === Number(params.age))))
                                pageModal.pageNo = 1
                            }}>Search</Button>
                        </div>
                    </div>
                    <div className="controlBtn">
                        <Button color={'green'} variant={'dashed'} size='small' onClick={() => {
                            setRenderId(-1)
                            useHandleForm.onReset()
                            setIsModalOpen(true)
                        }}>Add</Button>
                    </div>
                </>
            } actions={[
                <div className='footer'>
                    <Pagination total={tableData.length} showSizeChanger pageSize={pageModal.pageSize}
                                current={pageModal.pageNo}
                                showTotal={(total) => `Total ${total}`}
                                onChange={(page, size) => {
                                    setPageModal(prev => ({
                                        pageNo: size !== prev.pageSize ? 1 : page,
                                        pageSize: size,
                                    }))
                                }}
                    />
                </div>
            ]}>
                <Table
                    dataSource={pagedData}
                    columns={columns}
                    pagination={false}
                    style={{}}
                />
            </Card>
            <div className="update">
                <Modal
                    title={(renderId === -1 ? 'Add' : 'Update') + ' item'}
                    open={isModalOpen}
                    onOk={() => {
                        handleRef.current?.validator().then(values => {
                            let msg = ''
                            if (renderId === -1) {
                                setTableData(p => [...p, {...values, key: Date.now()}])
                                msg = '添加成功'
                            } else {
                                setTableData(p => p.map(it => (it.key === renderId ? {...it, ...values} : it)))
                                msg = '修改成功'
                            }
                            messageApi.success(msg)
                            setIsModalOpen(false)
                        }).catch(console.error)
                    }}
                    onCancel={() => {
                        setIsModalOpen(false)
                    }}
                >
                    <AdDynamicForm items={handleFormItems} ref={handleRef}/>
                </Modal>
            </div>
        </div>
    )
}

export default ZealBase;
css
.title {
    text-align: center;
    font-weight: bold;
    font-size: 18px;
    margin: 10px 0;
}

.search {
    margin: 10px 0;
}

.controlBtn {
    margin-bottom: 10px;
}

.ant-card .ant-card-body {
    padding: 0;
}

.search .searchBtn {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
}

.fControlBtn {
    display: flex;
    justify-content: center;
    gap: 10px;
}

.footer {
    display: flex;
    justify-content: center;
}