如何在React中使用ANTd创建动态表单输入字段



https://codesandbox.io/s/compassionate-sanderson-1m8nv?file=/src/App.js

我没能找到关于这个话题的很多信息。以下是我想要达到的目标:

我希望用户能够编辑数据库中已经存在的采购订单的一些详细信息,然后使用表单重新提交采购订单。原始采购订单的详细信息应该显示在表单输入字段中,用户可以通过这些字段直接更改它们,然后提交。

我不懂web开发,所以请原谅我。

我希望最终的表单对象看起来像这样:

{
po_number:"123abc",
carrier:"Fastway",
items: [{
item_code:"dnh75n",
quantity:"10",
special_requirements:"Add picture of happy dog"
},
{
item_code:"456def",
quantity:"4",
special_requirements:"Do not include lids"
}
]
}

生成的表单输入字段的数量将基于采购订单中有多少项。我在下面创建了一个简单的React组件来演示我要做的事情。或者直接签出上面的代码沙箱链接。任何帮助都会很感激。我甚至找不到关于如何对ANTd表单项进行分组以在采购订单中创建项目数组的信息。我在他们的网站上看到过很多动态表单的例子,但我想基于采购订单中已有的项目创建表单,而不是添加用户输入的字段。

import { Form, Input, Button } from 'antd';
//This is the order that already exists
const order = {
po_number:"123abc",
carrier:"Fastway",
items: [{
item_code:"dnh75n",
quantity:"10",
special_requirements:"Add picture of happy dog"
},
{
item_code:"456def",
quantity:"4",
special_requirements:"Do not include lids"
}
]
};

const GroupForm = () => {
const onFinish = values => {
console.log(values);
}

//Create form fields based off how many items are in the order
const itemInputs = order.items.map(item => {
return (
<div>
<b>Item{" " + item.item_code}</b>
<Form.Item name={item.item_code + "_quantity"} label="quantity">
<Input defaultValue={item.quantity} style={{width: "500px"}} />
</Form.Item>
<Form.Item name={item.item_code + "_requirements"} label="speacial requirements">
<Input defaultValue={item.special_requirements}  style={{width: "500px"}} />
</Form.Item>
</div>
);
});
return(
<div>
<Form onFinish={onFinish}>
<b>{"Order " + order.po_number}</b>

<Form.Item name="carrier" label="carrier">
<Input defaultValue={order.carrier} style={{width: "500px"}} />
</Form.Item>
<b>Order Items</b>
{itemInputs}
<Form.Item>
<Button type="primary" htmlType="submit"> Change Details </Button>
</Form.Item>
</Form>
</div>
);
}
export default GroupForm;

如果您使用的是antd版本4.9.0+,那么您可以利用Form.List上的initialValue属性。这允许您在数组的表单项上设置初始值。也可以在"Form"上设置"initialValues"属性。下面是使用前一种方法的最小可行示例。

import { Form, Input, Button, Space } from "antd";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import React from "react";
//Basic Idea
/* 
I want the user to be able to edit some details of a purchase order that already exists in the database,
then resubmit the order with a form.
The details of the purchase order should be orginally displayed in the form input fields,
and the user can change them directly via those fields. 
*/
//This is the order that already exists
const order = {
po_number: "123abc",
carrier: "Fastway",
items: [
{
item_code: "dnh75n",
quantity: "10",
special_requirements: "Add picture of happy dog"
},
{
item_code: "456def",
quantity: "4",
special_requirements: "Do not include lids"
}
]
};
const itemInputs = order.items
const GroupForm = () => {
const onFinish = (values) => {
console.log(values);
};
/**
* Edited: `const itemInputs = order.items` above
*/
//Create form fields based off how many items are in the order
// const itemInputs = order.items.map((item) => {
//   return {
//     item_code: item.item_code,
//     quantity: item.quantity,
//     special_requirements: item.special_requirements
//   };
// });
return (
<div>
<Form onFinish={onFinish}>
<b>{"Order " + order.po_number}</b>
<Form.Item name="carrier" label="carrier" initialValue={order.carrier}>
<Input style={{ width: "500px" }} />
</Form.Item>
<Form.Item
name="po_number"
label="PO number"
initialValue={order.po_number}
hidden
>
<Input />
</Form.Item>
<b>Order Items</b>
<Form.List name="items" initialValue={itemInputs}>
{(fields, { add, remove }) => (
<>
{fields.map((field) => (
<Space
key={field.key}
style={{ display: "flex", marginBottom: 8 }}
align="baseline"
>
<Form.Item
{...field}
name={[field.name, "item_code"]}
// no need anymore
// fieldKey={[field.fieldKey, "item_code"]}
>
<Input placeholder="Item Code" />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "quantity"]}
// no need anymore
// fieldKey={[field.fieldKey, "quantity"]}
>
<Input placeholder="Quantity" />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "special_requirements"]}
// no need anymore
// fieldKey={[field.fieldKey, "special_requirements"]}
>
<Input placeholder="Quantity" />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={add}
block
icon={<PlusOutlined />}
>
Add item
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
{" "}
Change Details{" "}
</Button>
</Form.Item>
</Form>
</div>
);
};
export default GroupForm;
// I want to submit a form object that looks like this. E.g.
// This is what 'onFinish' should display in the console
/*
{
po_number:"123abc",
carrier:"Fastway",
items: [{
item_code:"dnh75n",
quantity:"10",
special_requirements:"Add picture of happy dog"
},
{
item_code:"456def",
quantity:"4",
special_requirements:"Do not include lids"
}
]
}
*/

多亏了Scratch'N'Purr,我使用了您的解决方案来进一步将字段放入一个和表中。

首先是一个简短的说明:fieldKey={[field.fieldKey, "quantity"]}从以前的解决方案不适合我,但把它改为key={[field.key, "quantity"]}的技巧。

//define the columns for the table
const columns = [
{
title: "ITEM#",
dataIndex: "item_code",
key: "item_code",
width: "12%",
//use the field here to get all infos for the form
render: (_, field) => (
<Form.Item
{...field}
name={[field.name, "item_code"]}
key={[field.key, "item_code"]}
noStyle
>
<Input placeholder="ITEM#" />
</Form.Item>
),
},
{
title: "Quantity",
dataIndex: "quantity",
key: "quantity",
render: (_, field) => (
<Form.Item
{...field}
name={[field.name, "quantity"]}
//@ts-ignore
key={[field.key, "quantity"]}
noStyle
>
<Input placeholder="Quantity" />
</Form.Item>
),
}];
const GroupForm = () => {
const onFinish = (values) => {
console.log(values);
};
//Create form fields based off how many items are in the order
const itemInputs = order.items.map((item) => {
return {
item_code: item.item_code,
quantity: item.quantity,
special_requirements: item.special_requirements,
};
});
return (
<div>
<Form onFinish={onFinish}>
<b>{"Order " + order.po_number}</b>
<Form.Item name="carrier" label="carrier" initialValue={order.carrier}>
<Input style={{ width: "500px" }} />
</Form.Item>
<Form.Item
name="po_number"
label="PO number"
initialValue={order.po_number}
hidden
>
<Input />
</Form.Item>
<b>Order Items</b>
<Form.List name="items" initialValue={itemInputs}>
{(fields, { add, remove }, { errors }) => (
<>
{/* This is where to put the table. As a data source i used the fields */}
<Table dataSource={fields} columns={columns} pagination={false} />
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{ width: "60%" }}
icon={<PlusOutlined />}
>
Add field
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
{" "}
Change Details{" "}
</Button>
</Form.Item>
</Form>
</div>
);
};

最新更新