如何验证Form.List中指定索引位置的全部子字段?
问题场景
假设我们有如下表单数据:
{ phoneNumbers: [ { number: "123456789", type: "MOBILE" }, { number: "987654321", type: "HOME" }, ] }
使用Ant Design的Form.List遍历渲染字段:
<Form.List name="phoneNumbers"> {(fields, { add, remove }) => { return fields.map((field) => ( <div key={field.key}> <Form.Item name="number">...</Form.Item> <Form.Item name="type">...</Form.Item> <Button onClick={() => handleSaveSingle(field.index)}>单独保存</Button> </div> )); }} </Form.List>
需求是点击「单独保存」按钮时,验证并保存对应索引行的所有字段,但仅知道列表名(如phoneNumbers)和索引,不清楚该行下每个Form.Item的具体名称,尝试form.validateFields(["phoneNumbers", index])无法生效。
解决方案
方法1:通过表单字段信息筛选当前行子字段路径
利用form.getFieldsInfo()获取所有字段的完整路径,筛选出属于目标行的子字段,再批量验证:
const handleSaveSingle = async (index) => { const listName = "phoneNumbers"; const rowPath = [listName, index]; // 获取所有字段的元信息 const allFields = form.getFieldsInfo(); // 筛选出当前行下的所有子字段路径 const rowFieldPaths = allFields .filter(fieldInfo => fieldInfo.name.length > rowPath.length && fieldInfo.name.slice(0, rowPath.length).every((item, idx) => item === rowPath[idx]) ) .map(fieldInfo => fieldInfo.name); try { // 验证筛选出的子字段 const values = await form.validateFields(rowFieldPaths); // 提取当前行的结构化数据 const rowData = {}; rowFieldPaths.forEach(path => { const fieldName = path[path.length - 1]; rowData[fieldName] = values[path.join('.')]; }); // 调用保存接口 console.log('待保存行数据:', rowData); } catch (errorInfo) { console.log('验证失败:', errorInfo); } };
方法2:给行容器嵌套外层Form.Item
将当前行的所有字段包裹在一个Form.Item中,设置name为当前行的路径(field.name),这样直接验证该路径就能触发所有子字段的规则校验:
<Form.List name="phoneNumbers"> {(fields, { add, remove }) => { return fields.map((field) => { const handleSave = async () => { try { // 直接验证当前行的完整路径 const values = await form.validateFields([field.name]); console.log('待保存行数据:', values[field.name.join('.')]); // 调用保存接口 } catch (errorInfo) { console.log('验证失败:', errorInfo); } }; return ( <Form.Item key={field.key} name={field.name}> <div> <Form.Item name="number" rules={[{ required: true, message: '请输入号码' }]}>...</Form.Item> <Form.Item name="type" rules={[{ required: true, message: '请选择类型' }]}>...</Form.Item> <Button onClick={handleSave}>单独保存</Button> </div> </Form.Item> ); }); }} </Form.List>
这种方式会让表单自动将内部字段合并为行对象,验证时会遍历子字段触发各自的规则。
方法3:渲染时收集当前行子字段名称
如果子字段是固定或可提前获取的,在Form.List渲染时收集子字段名,拼接成完整路径后验证:
<Form.List name="phoneNumbers"> {(fields, { add, remove }) => { return fields.map((field) => { // 假设已知当前行的子字段名称,动态场景可通过遍历子组件提取 const subFieldNames = ["number", "type"]; const rowFieldPaths = subFieldNames.map(name => field.name.concat(name)); const handleSave = async () => { try { const values = await form.validateFields(rowFieldPaths); const rowData = subFieldNames.reduce((acc, name) => { acc[name] = values[rowFieldPaths.find(p => p.includes(name)).join('.')]; return acc; }, {}); console.log('待保存行数据:', rowData); // 调用保存接口 } catch (errorInfo) { console.log('验证失败:', errorInfo); } }; return ( <div key={field.key}> <Form.Item name="number">...</Form.Item> <Form.Item name="type">...</Form.Item> <Button onClick={handleSave}>单独保存</Button> </div> ); }); }} </Form.List>
内容的提问来源于stack exchange,提问作者syydi
相关产品推荐
相关产品推荐

