30

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?

Sergio
  • 28,539
  • 11
  • 85
  • 132
vladimirp
  • 1,474
  • 5
  • 17
  • 24

8 Answers8

50

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

Alex Kolarski
  • 3,255
  • 1
  • 25
  • 35
21

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>
    </>
  )
}
Chhaileng
  • 2,428
  • 1
  • 27
  • 24
11

You can study official example: https://ant.design/components/form/#components-form-demo-form-in-modal

benjycui
  • 376
  • 1
  • 3
  • 7
    A link to a potential solution is always welcome, but please [add context around the link](http://meta.stackoverflow.com/a/8259/169503) so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. Take into account that being *barely more than a link to an external site* is a possible reason as to [Why and how are some answers deleted?](http://stackoverflow.com/help/deleted-answers). – zuazo Dec 27 '16 at 02:07
  • Note: this example is use `Form.useForm()` hook which means it only work for antd v4 – Lin Du Feb 11 '22 at 07:09
6

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>
    );
}
vladimirp
  • 1,474
  • 5
  • 17
  • 24
1

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.

JacopoStanchi
  • 1,962
  • 5
  • 33
  • 61
1

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

Wasif
  • 183
  • 2
  • 3
  • 14
0

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.

Reference

0

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>
        </>
    )
}
Closery
  • 828
  • 9
  • 14