Integrate Ant Design Form with Modal

Viewed 3903

I am pretty new to React and JS, and I am currently trying to create a component to integrate the antd form with modal so that I could utilize the form functionalities such as "validation".

Here is my code:

The function to post the request:

import baseUrl from "./baseUrl";

export async function _postSchoolRollOutRequest(schoolRollOutRequestForm) {
  try {
    const response = await fetch(
      `${baseUrl}/feedbacks/request/schoolRollOutRequest`,
      {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
        body: JSON.stringify(schoolRollOutRequestForm),
      }
    );
    const data = await response.json();
    console.log("Post school roll out form success!");
    return data;
  } catch (e) {
    console.log("Post school roll out form failed!", e);
  }
}

The component of integrating the form with modal:

import React, { useState } from "react";
import { Modal, Button, Form, Input, Radio } from "antd";
import { _postSchoolRollOutRequest } from "../../api/feedbacksApi";

import "./PopUp.scss";

export default (props) => {
  const FormItem = Form.Item;

  const [visible, setVisible] = useState(false);
  const showModal = () => {
    setVisible(true);
  };

  const handleOk = (schoolRollOutRequestForm) => {
    _postSchoolRollOutRequest(schoolRollOutRequestForm);
    setVisible(false);
  };

  const handleCancel = () => {
    setVisible(false);
  };

  return (
    <>
      <Button type="primary" onClick={showModal}>
        Roll-out My School!
      </Button>
      <Modal
        destroyOnClose={true}
        visible={visible}
        title="Roll-out Request"
        onCancel={handleCancel}
        footer={[
          <Button
            block
            key="submit"
            type="primary"
            onClick={(feedbackSubmission) =>
              handleOk({
                shoolName: feedbackSubmission.shoolName,
                otherFeedback: feedbackSubmission.otherFeedback,
                contact: feedbackSubmission.contact,
              })
            }
          >
            Roll-out My School!
          </Button>,
        ]} 
        width={400}
      >
        <div className={"modal-body center"}>
          <Form layout="vertical">
            <Form.Item
              label="Schools Name"
              name="schoolName"
              rules={[{ required: true }]}
            >
              {<Input type="text" label="schoolName" placeholder="UT Austin" />}
            </Form.Item>
            <FormItem
              label="Any other requirements/feedback (optional)"
              name="otherFeedback"
            >
              {<Input type="textarea" placeholder="abcd..." />}
            </FormItem>
            <FormItem label="How do we contact you? (optional)" name="contact">
              {<Input type="text" placeholder="abcd@email.com" />}
            </FormItem>
          </Form>
        </div>
      </Modal>
    </>
  );
};

However, I encountered two problems that really confused me:

  1. I think the button at the footer does not trigger the form's onFinish so that the form's validation does not work, I am wondering could I get any clue about the best practice for my situation?

  2. I tried to fake a json for "handleOk" then later "_postSchoolRollOutRequest", but it seems like my backend get a request with an empty payload, could I get any insights about this problem as well?

1 Answers

Code Sandbox: https://codesandbox.io/s/antdesignmodalform-stackoverflow-3yv4h?file=/index.js:920-3529

Firstly submit button should be inside form tag. If it is outside form tag then you need to make use of form attribute to trigger it.

In your case modal is always outside the form, so you have to link submit button with the form.

Here is how you can achieve it using ANT design.

Action Handler Code (if you are using redux then modify callback part as per your requirement)

export async function _postSchoolRollOutRequest(
  schoolRollOutRequestForm,
  callback
) {
  const baseUrl = "http://testing.com";

  console.log("form values", schoolRollOutRequestForm);
  try {
    const response = await fetch(
      `${baseUrl}/feedbacks/request/schoolRollOutRequest`,
      {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json"
        },
        body: JSON.stringify(schoolRollOutRequestForm)
      }
    );
    const data = await response.json();
    console.log("Post school roll out form success!");

    callback(response.status, data);
  } catch (e) {
    callback(e.status);
    console.log("Post school roll out form failed!", e);
  }
}

Form component

const FormModal = () => {
  const [form] = Form.useForm();
  const [visible, setVisible] = useState(false);
  const [postData, setPostData] = useState({
    loading: false,
    error: false,
    data: []
  });

  const onSubmit = (values) => {
    setPostData({ ...postData, loading: true, error: false });
    _postSchoolRollOutRequest(values, (status, data) => {
      if (status === 200) {
        form.resetFields();
        setPostData({ ...postData, loading: false, data: data });
      } else {
        setPostData({
          ...postData,
          loading: false,
          error: true,
          data: "Post school roll out form failed!"
        });
      }
    });
  };

  return (
    <>
      <Button
        type="primary"
        onClick={() => {
          setVisible(true);
        }}
      >
        click to open form
      </Button>
      <Modal
        visible={visible}
        title="Post  data"
        okText="Submit"
        cancelText="Cancel"
        onCancel={() => {
          setVisible(false);
        }}
        footer={[
          <Button key="cancel" onClick={() => setVisible(false)}>
            Cancel
          </Button>,
          <Button
            key="submit"
            type="primary"
            loading={postData.loading}
            onClick={() => {
              form
                .validateFields()
                .then((values) => {
                  onSubmit(values);
                })
                .catch((info) => {
                  console.log("Validate Failed:", info);
                });
            }}
          >
            Submit
          </Button>
        ]}
      >
        <Form
          form={form}
          layout="vertical"
          name="form_in_modal"
          initialValues={{
            modifier: "public"
          }}
        >
          <Form.Item
            label="Schools Name"
            name="schoolName"
            rules={[
              {
                required: true,
                message: ""
              }
            ]}
          >
            <Input />
          </Form.Item>
          <Form.Item
            label="Any other requirements/feedback (optional)"
            name="otherFeedback"
          >
            <Input type="textarea" />
          </Form.Item>
          <Form.Item label="How do we contact you? (optional)" name="contact">
            <Input />
          </Form.Item>

          {postData.error && (
            <>
              <br />
              <span style={{ color: "red" }}>{postData.data}</span>
            </>
          )}
        </Form>
      </Modal>
    </>
  );
};
Related