Reputation: 609
Im using form list from antd with react.js https://ant.design/components/form/#Form.List
I have a simple form list here. I can add and remove fields.
Sometimes I want to reset the form remove items Ive added.
const [form] = Form.useForm();
...
<Form form={form} name="control-hooks">
<Form.List name="fruits">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Row key={key}>
<Col span={24}>
<Form.Item {...restField} name={[name, 'color']}>
<Select placeholder="Select fruit">{
fruits.map((fruit, index) =>
<Option key={index} value={fruit.color}>
{fruit.color}
</Option>
)
}
</Select>
</Form.Item>
<Form.Item {...restField} name={[name, 'quantity']} initialValue={1}>
<InputNumber placeholder="Quantity" />
</Form.Item>
<Button onClick={() => remove(name)}>Remove</Button>
</Col>
</Row>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()}>
Add
</Button>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form>
...
<Button type="primary" onClick={resetForm}>Reset from outside</Button>
This is my try:
const resetForm = () => {
form.resetFields();
}
Any ideas how I can make it? Thank you
Edit: I added more detailed explanation
Edit2
https://codesandbox.io/s/priceless-robinson-6q577?file=/src/index.js
I tried to make a example and for some reason it worked .... what is the difference???
Edit3
Solution:
I found the problem! It was the initialValue. If I have initialValue in any of my Form.Item, antd will not remove those dynamically added fields. Thanks for the help
Upvotes: 1
Views: 11871
Reputation: 6049
Antd Form.List
component provides a way to add the same fields again in the form dynamically. The children of the component is expecting to be used as function of a child just like render prop
. So, this render function is going to be invoked by antd Form.List
component. We don't have controlled over the invocation of the function of a child.
The type of children of Form.List
is given below. I have taken from here.
export interface FormListFieldData {
name: number;
key: number;
}
export interface FormListOperation {
add: (defaultValue?: StoreValue, insertIndex?: number) => void;
remove: (index: number | number[]) => void;
move: (from: number, to: number) => void;
}
export interface FormListProps {
// other types
children: (
fields: FormListFieldData[],
operation: FormListOperation,
meta: { errors: React.ReactNode[]; warnings: React.ReactNode[] },
) => React.ReactNode;
}
So, we can use the fields, operation and meta data in the children function.
Your below snippet, doesn't do that Antd Form.List is expected to do. You're not calling a children function, its Antd Form.List component who is going to call the children function with some defined props that is mentioned in the above type snippet.
const [formFields, setFormFields] = useState([]); // you don't need any state.
...
<Form.List>
{formFields => ( // error, it should be fields that antd expects
<div>
{formFields.map(formField => (
<Form.Item {...formField}>
<Input />
</Form.Item>
))}
</div>
)}
</Form.List>
Basic example of Form.List with reset and no inputs is hidden below, please unhide to be visible:
// don't run it, it just to hide long snippets
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Form, Input, Button, Space } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
const Demo = () => {
const [form] = Form.useForm();
const onFinish = values => {
console.log('Received values of form:', values);
};
const onReset = () => {
form.resetFields()
}
return (
<Form form={form} name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
<Form.List name="hello">
{(fields, { add }) => (
<>
{fields.map(({ key, name, }) => (
<Space key={key} style={{ display: 'flex', marginBottom: 8 }} align="baseline">
<Form.Item
name={[name, 'first']}
rules={[{ required: true, message: 'Missing first name' }]}
>
<Input placeholder="First Name" />
</Form.Item>
<Form.Item
name={[name, 'last']}
rules={[{ required: true, message: 'Missing last name' }]}
>
<Input placeholder="Last Name" />
</Form.Item>
</Space>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button type="secondary" onClick={onReset}>
Reset
</Button>
</Form.Item>
</Form>
);
};
ReactDOM.render(<Demo />, document.getElementById('container'));
// dont run it
form.resetFields()
will clear the input values and remove the inputs from the form if the Form.list
has a name property/attribute associated with it.
Upvotes: 1
Reputation: 6019
The values provided as the initialValues should be used by the reset function.
<Form
...
initialValues={{first_name: 'John'}}
/>
If you want to change some of them afterwards the way to go is;
form.setFieldsValue({ first_name: 'John' });
to do that your fields should have the name properties defined here.
<Form.Item
name="first_name"
Upvotes: 5