Reputation: 1554
In my component's render method I have antd Modal component as a parent and antd Form component as a child:
render() {
const myForm = Form.create()(AddNewItemForm);
...
return (
...
<Modal
title="Create new item"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
wrapClassName="vertical-center-modal"
okText="Save new item"
width="600"
>
<myForm />
</Modal>
...
How can I submit my form by clicking the Modals Save button?
Upvotes: 32
Views: 80320
Reputation: 968
Simple way to do this in 2021 is making customized footer for modal
import { useState } from 'react'
import { Modal, Button, Form, Input } from 'antd'
export default function BasicModal() {
const [form] = Form.useForm()
const [isModalVisible, setIsModalVisible] = useState(false)
const showModal = () => setIsModalVisible(true)
const handleCancel = () => {
setIsModalVisible(false)
form.resetFields()
}
const handleOk = () => {
form.submit()
}
const onFinish = () => {
console.log('Form submited!')
setIsModalVisible(false)
}
return (
<>
<Button type="primary" onClick={showModal}>
Show Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
footer={[
<Button key="back" onClick={handleCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={handleOk}>
Submit
</Button>,
]}
>
<Form labelCol={{ xs: { span: 6 } }} wrapperCol={{ xs: { span: 12 } }} form={form} onFinish={onFinish} scrollToFirstError>
<Form.Item name="input1" label="Input 1" rules={[{ required: true, message: "This field is required." }]}>
<Input />
</Form.Item>
<Form.Item name="input2" label="Input 2" rules={[{ required: true, message: "This field is required." }]}>
<Input />
</Form.Item>
</Form>
</Modal>
</>
)
}
Upvotes: 1
Reputation: 2516
My solution is using hooks
import { Button, Modal, Form } from 'antd';
export default function ModalWithFormExample() {
const [visible, setVisible] = useState(false);
const [form] = Form.useForm();
const showModal = () => {
setVisible(true)
}
const handleSubmit = (values) => {
console.log(values)
}
const handleCancel = () => {
setVisible(false)
form.resetFields()
};
return (
<>
<Button onClick={showModal}>Open Modal</Button>
<Modal visible={visible} onOk={form.submit} onCancel={handleCancel}>
<Form form={form} onFinish={handleSubmit}>
{/* Any input */}
</Form>
</Modal>
</>
)
}
Upvotes: 25
Reputation: 867
My solution 1st solution
...
handleOk = (e) => {
e.preventDefault();
this.form.validateFields((err, values) => {
//do your submit process here
});
}
//set ref form
formRef = (form) => {
this.form = form;
}
render() {
const myForm = Form.create()(AddNewItemForm);
...
return (
...
<Modal
title="Create new item"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
wrapClassName="vertical-center-modal"
okText="Save new item"
width="600"
>
<myForm
ref={this.formRef}
/>
</Modal>
...
or you can use this solution
...
handleOk = (e) => {
e.preventDefault();
this.form.validateFields((err, values) => {
//do your submit process here
});
}
render() {
const myForm = Form.create()(AddNewItemForm);
...
return (
...
<Modal
title="Create new item"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
wrapClassName="vertical-center-modal"
okText="Save new item"
width="600"
>
<myForm
wrappedComponentRef={(form) => this.formRef = form}
/>
</Modal>
...
The idea is to set the ref for wrapped the form component.
Please see the reference below.
Upvotes: 0
Reputation: 213
Now, react hooks are out you can achieve the same thing using hooks also. By creating a wrapper component for the modal and used that component where the form is.
Wrapper Component:
<Modal
visible={state}
centered={true}
onCancel={() => setState(false)}
title={title}
destroyOnClose={true}
footer={footer}>
{children}
</Modal>
Form Component:
<WrapperModal
state={modalState}
setState={setModal}
title='Example Form'
footer={[
<button onClick={handleSubmit}>
SUBMIT
<button/>
]}>
<Form>
<Form.Item label='name '>
{getFieldDecorator('name ', {
rules: [
{
required: true,
message: 'please enter proper name'
}
]
})(<Input placeholder='name'/>)}
</Form.Item>
</Form>
</WrapperModal>
here i had created a wrapper modal component which have all the necessary api for the modal, also i am creating a custom buttons for my modal
Upvotes: 1
Reputation: 3425
There is a new solution that looks much cleaner:
<Form id="myForm">
...
<Modal
...
footer={[
<Button form="myForm" key="submit" htmlType="submit">
Submit
</Button>
]}
>
<CustomForm />
</Modal>
This works because of the Button's form attribute. Browser support
Original solution's author: https://github.com/ant-design/ant-design/issues/9380
Upvotes: 62
Reputation: 2146
My solution was to disable the modal's footer and create my own submit button:
<Modal footer={null}>
<Form onSubmit={this.customSubmit}>
...
<FormItem>
<Button type="primary" htmlType="submit">Submit</Button>
</FormItem>
</Form>
</Modal>
No need to wrap the modal with this solution.
Upvotes: 1
Reputation: 384
You can study official example: https://ant.design/components/form/#components-form-demo-form-in-modal
Upvotes: 12
Reputation: 1554
My solution was to wrap modal dialogue and form components in a new wrapper parent component in which I validate the child form component in handleCreate method. I have used the ref attribute to reference the myForm child component inside the FormOnModalWrapper component. I am passing the parent handlers via props from the wrapper parent component to myForm component instance.
class FormOnModalWrapper extends React.Component {
...
constructor(props) {
this.state =
{
visible: false
....
}
...
showModal = () => {
this.setState({
visible: true,
});
}
handleCreate = () => {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
form.resetFields();
this.setState({ visible: false });
});
}
saveFormRef = (form) => {
this.form = form;
}
render() {
...
const myForm= Form.create()(CrateNewItemFormOnModal);
...
return (
<div>
<Button onClick={this.showModal}>Add</Button>
<myForm
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
ref={this.saveFormRef}
/>
</div>
);
}
In CrateNewItemFormOnModal component class I have a modal dialogue component as a parent and form component as a child:
export default class AddNewItemForm extends React.Component {
render() {
...
const { visible, onCancel, onCreate, form } = this.props;
...
return (
<Modal
title="Create new item"
visible={visible}
onOk={onCreate}
onCancel={onCancel}
okText="Create"
>
<Form>
...
</Form>
</Modal>
);
}
Upvotes: 6