Form.List 利用Form.Item的name来深层绑定
name为索引数组,[index,name] : [数据的第几个(从0开始),数据绑定参数名]
合起来代表的含义: map[index].name
name绑定正确才能触发form的校验和绑定
最简单的使用:
只使用FornList
下述代码可以生成一个可增删的列表
fields为jonData数组处理后的数据,fileld.name即数据绑定的index,form根据该数据来进行增删
<Form
ref={formvalue}
form={form}
autoComplete="off"
initialValues={{
jonData: [
{
building: "22",
version: "",
},
],
}}
>
<Form.List name="jonData">
{(fields, { add, remove }) => (
<div
style={{
display: "flex",
rowGap: 16,
flexDirection: "column",
}}
>
{fields.map((field) => (
<Card
size="small"
title={`Item ${field.name + 1}`}
key={field.key}
extra={
<CloseOutlined
onClick={() => {
remove(field.name);
}}
/>
}
>
<Form.Item label="building" name={[field.name, "building"]}>
<Input />
</Form.Item>
<Form.Item label="version" name={[field.name, "version"]}>
<Input />
</Form.Item>
</Card>
))}
<Button type="dashed" onClick={() => add()} block>
+ Add Item
</Button>
</div>
)}
</Form.List>
</Form>
深层嵌套:
在Form中本身支持嵌套模式,其实现也同样依赖于name数组
下述代码用 name={[field.name, "doorButton", "frontOpen"]}绑定了jonData中每一项的doorButton.frontOpen
<Form
ref={formvalue}
form={form}
autoComplete="off"
initialValues={{
jonData: [
{
building: "22",
version: "0101",
doorButton: {
frontOpen: 0,
backOpen: 1,
},
},
],
}}
>
<Form.List name="jonData">
{(fields, { add, remove }) => (
<div
style={{
display: "flex",
rowGap: 16,
flexDirection: "column",
}}
>
{fields.map((field) => (
<Card
size="small"
title={`Item ${field.name + 1}`}
key={field.key}
extra={
<CloseOutlined
onClick={() => {
remove(field.name);
}}
/>
}
>
<Form.Item label="楼栋" name={[field.name, "building"]}>
<Input />
</Form.Item>
<Form.Item label="version" name={[field.name, "version"]}>
<Input />
</Form.Item>
<Form.Item
label='深层绑定'
name={[field.name, "doorButton", "frontOpen"]}
>
<InputNumber min={0} placeholder={translate["请输入"]} />
</Form.Item>
</Card>
))}
<Button type="dashed" onClick={() => add()} block>
+ Add Item
</Button>
</div>
)}
</Form.List>
</Form>
动态数据更新
如果需要某一部分随着表单中的某一项的值改变而改变,form提供了shouldUpdate
prevValues为之前的值, currentValues为改变之后的值,同样使用name绑定的层级来获取
getFieldValue([*,*,*])可以获取某个字段的值-实时变化-用以shouldUpdate更新,必须用该函数包裹dom才会更新
<Form.Item
// 楼栋信息变化--此组件包裹的内容将调用更新
shouldUpdate={(prevValues, currentValues) =>
prevValues.jonData[field.name]?.building !==
currentValues.jonData[field.name]?.building
}
>
{/* getFieldValue([*,*,*])可以获取某个字段的值-实时变化-用以shouldUpdate更新 */}
{({ getFieldValue }) =>
getFieldValue(["jonData", field.name, "building"]) !=="building" ? (
<>
<Form.Item label="key" name={[field.name, "key"]}>
<Input />
</Form.Item>
<Form.Item
label="deviceId"
name={[field.name, "deviceId"]}
>
<Input />
</Form.Item>
</>
) : null
}
</Form.Item>
多层Form.List
我们可以在list中嵌套list,正如上述的fields遍历一样,form.item绑定了name,即可在该层级上拿到绑定数据,用绑定数据来遍历
示例:
下方代码,floorMap即二层绑定
<Form
ref={formvalue}
form={form}
autoComplete="off"
initialValues={{
jonData: [
{
building: "22",
version: "0101",
doorButton: {
frontOpen: 0,
backOpen: 1,
},
floorMap: [
{
floor: 1,
},
],
},
],
}}
>
<Form.List name="jonData">
{(fields, { add, remove }) => (
<div
style={{
display: "flex",
rowGap: 16,
flexDirection: "column",
}}
>
{fields.map((field) => (
<Card
size="small"
title={`Item ${field.name + 1}`}
key={field.key}
extra={
<CloseOutlined
onClick={() => {
remove(field.name);
}}
/>
}
>
<Form.Item label="楼building" name={[field.name, "building"]}>
<Input />
</Form.Item>
<Form.Item label="version" name={[field.name, "version"]}>
<Input />
</Form.Item>
<Form.Item label="floorMap">
<Form.List name={[field.name, "floorMap"]}>
{(subFields, subOpt) => (
<>
{subFields.map((subField) => (
<Space key={subField.key}>
<Form.Item
noStyle
name={[subField.name, "floor"]}
>
<Input placeholder="floor" />
</Form.Item>
<CloseOutlined
onClick={() => {
subOpt.remove(subField.name);
}}
/>
</Space>
))}
<Button
type="dashed"
onClick={() => subOpt.add()}
block
>
+ Add Sub Item
</Button>
</>
)}
</Form.List>
</Form.Item>
</Card>
))}
<Button type="dashed" onClick={() => add()} block>
+ Add Item
</Button>
</div>
)}
</Form.List>
</Form>
双层可编辑表格绑定
将表格中的可编辑的表单与form绑定,直接利用form的表单绑定与校验,可节省很多开发时间
用antd的table ,将tr td单拆出来,name绑定原理也是当层[index,参数名]
table的表格数据绑定即本层的floorMap----subFields
实例:
完整代码:
import React, { useContext, useEffect, useRef, useState } from "react";
import { Button, Form, Input, Card, Table, Space } from "antd";
import { CloseOutlined } from "@ant-design/icons";
import "./index.scss";
const ExitTable = () => {
const [form] = Form.useForm();
const formvalue = useRef(null);
const handleSubmit = () => {
console.log(222222, form.getFieldsValue());
};
//表格配置
const defaultColumns = [
{
title: "floor",
dataIndex: "floor",
width: "30%",
editable: true,
},
{
title: "floorName",
dataIndex: "floorName",
editable: true,
},
{
title: "删除",
dataIndex: "delete",
editable: true,
},
];
const columns = defaultColumns.map((col, index) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
col: col,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
}),
};
});
useEffect(() => {
form.setFieldsValue({
jonData: [
{
liftId: 1,
type: "",
building: "22",
version: "0101",
key: "xsxsx",
deviceId: "xsx",
doorButton: {
frontOpen: 0,
backOpen: 1,
},
floorMap: [
{
floor: 1,
},
],
},
],
});
}, []);
return (
<div>
<Form
ref={formvalue}
labelCol={{
span: 5,
}}
wrapperCol={{
span: 18,
}}
form={form}
name="dynamic_form_complex"
style={{
maxWidth: 700,
}}
autoComplete="off"
initialValues={{
jonData: [],
}}
>
<Form.List name="jonData">
{(fields, { add, remove }) => (
<div
style={{
display: "flex",
rowGap: 16,
flexDirection: "column",
}}
>
{fields.map((field) => (
<Card
size="small"
title={`Item ${field.name + 1}`}
key={field.key}
extra={
<CloseOutlined
onClick={() => {
remove(field.name);
}}
/>
}
>
<Form.Item label="building" name={[field.name, "building"]}>
<Input />
</Form.Item>
<Form.Item label="version" name={[field.name, "version"]}>
<Input />
</Form.Item>
<Form.Item label="floorMap">
<Form.List name={[field.name, "floorMap"]}>
{(subFields, subOpt) => (
<>
<Button
onClick={() => {
subOpt.add();
}}
>
新增
</Button>
<Table
components={{
body: {
cell: ({
title,
editable,
children,
dataIndex,
record,
col,
...restProps
}) => {
return (
<td {...restProps}>
{record && dataIndex == "delete" ? (
<Button
onClick={() => {
subOpt.remove(record.name);
}}
>
删除
</Button>
) : (
record && (
<Form.Item
style={{
margin: 0,
}}
name={[record.name, dataIndex]}
// rules={[
// {
// required: true,
// message: `${title} is required.`,
// },
// ]}
>
<Input />
</Form.Item>
)
)}
</td>
);
},
},
}}
rowClassName={() => "editable-row"}
bordered
dataSource={subFields}
columns={columns}
rowKey="key"
pagination={false}
/>
</>
)}
</Form.List>
</Form.Item>
</Card>
))}
<Button type="dashed" onClick={() => add()} block>
+ Add Item
</Button>
</div>
)}
</Form.List>
</Form>
<Button onClick={handleSubmit}>提交</Button>
</div>
);
};
export default ExitTable;
一些常用函数
1.设置表单值()
设置表单值--总体设置setFieldsValue
form.setFieldsValue({
jonData: [
{
building: "22",
version: "0101",
doorButton: {
frontOpen: 0,
backOpen: 1,
},
},
],
});
设置指定位置的值 --单个设置 setFieldValue
form.setFieldValue(
[
"jonData",
field.name,
"floorMap",
subField.name,
"floorKey",
],
'新值'
);
}}
2.获取表单值
获取全部表单的值getFieldsValue
form.getFieldsValue()
获取指定位置的值 getFieldValue
form.getFieldValue([
"jonData",
field.name,
"building",
])
3.触发表单校验validateFields
form.validateFields().then(()=>{}).catch(()=>{})
表单校验失败滚动到初始位置
form.validateFields().then(()=>{}).catch((error)=>{
form.scrollToField(error.errorFields[0].name)
})