'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.
Solution 1:[1]
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>
</>
);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Nouman Rafique |

