Base
WebReactAntd

Working with Antd Form

Antd have built in form management and support complex usage. It might seem overwhelming and hard to work with it for beginner or antd first time user. Here are some notes I tried to collect for my own future reference.

Preparations / Basics

  1. Wrap the whole form with Form component.
  2. Create form hook through Form.useForm:
const [form] = Form.useForm();
  1. Make sure to wrap each fields with Form.Item and define name (similar concept like react-hook-form or formik).

Things to Aware with Form

  1. Attach form state to Form.
  2. Define initialValues with state / immutable, not normal object. Why? Turns out anything passed to initialValues is prone to be unstable / becomes mutable. I tried to work around it with making sure passing state into it as state is immutable. This must be awared especially after switching back and forth between pages.
  3. Form provide onFinish that will only be triggered when submit and validation is success.
  4. Form provide onFailure that will be triggered when submit and validation is not passing.
  5. Form.Item provide rules to define field validation.
  6. Form initialValues will only work or mapped to Form.Item or Form.List. If there's an attribute which doesn't shown / rendered using Form.Item / Form.List, it won't be mapped / assigned.
  7. To make attribute still exist but the UI hidden, don't use null render. Use style.display: 'none'

Form Submit

For submit button which are not a descendant of the form:

  • define id in Form

  • define form in the submit button with the value same as id being defined in Form

  • examples:

    const FORM_KEY = 'form_id';
     
    ...
     
       <Form
        form={form}
        id={FORM_KEY}
        ...
       >
          ...
       </Form>
     
       ...
     
       <Button
        htmlType="submit"
        form={FORM_KEY}
       >
          Submit
       </Button>
    const FORM_KEY = 'form_id';
     
    ...
     
       <Form
        form={form}
        id={FORM_KEY}
        ...
       >
          ...
       </Form>
     
       ...
     
       <PopConfirm
        okButtonProps={{ htmlType: 'submit', form: FORM_KEY }}
       >
        <Button>Submit</Button>
       </PopConfirm>

Actually, it's a web standard 😄 References:

Things to Aware with Inputs

Input, Select, NumberInput

  1. For general purpose inputs, use Input component.
  2. For numeric inputs and expecting form state to also receive number, use NumberInput component.
  3. For formatted number input, use NumericInput of react-number-format and set customInput prop as Input.
  4. For switch toggle input, use valuePropName="checked" on the Form.Item wrapper of the switch.

⚠️ Do Not Put Multiple Children inside Form.Item

// this will make the form validation not working / not able to detect values
 
<Form.Item>
   <Input ... /> // or other antd input components
 
   <Typography.Text>Some Text<Typography.Text> // DO NOT PUT IT HERE, it will make the form item not working properly
</Form.Item>

Working with Array fields

  1. Form.List can be used for array property / attribute of the form shape.
  2. Form.List provide render function children: (fields, { add, remove, move }) => React.ReactNode
  3. We can combine Form.List with Table and pass fields as Table's dataSource.

Useful References

Form Item Persistency

For cases where the form item value need to be persisted whether shown or not

Keep the Form Values Persistent

Use the preserve property in Form.Item or Form.List. This ensures the form values persist even if the component is unmounted.

<Form.List name="items" preserve>
  {(fields, { add, remove }) => (
    <>
      {fields.map(({ key, name, ...restField }) => (
        <Form.Item {...restField} name={[name, "field"]} key={key}>
          <Input placeholder="Field" />
        </Form.Item>
      ))}
      <Button onClick={() => add()}>Add Field</Button>
    </>
  )}
</Form.List>

References: https://ant.design/components/form#form (preserve)

Working with Collapsible

Set destroyInactivePanel to false for the collapsible component. This keeps the panel content in the DOM even when collapsed, so no values are lost.

<Collapse destroyInactivePanel={false}>
  <Collapse.Panel header="Panel" key="1">
    <Form.List name="items">
      {(fields, { add, remove }) => (
        <>
          {fields.map(({ key, name, ...restField }) => (
            <Form.Item {...restField} name={[name, "field"]} key={key}>
              <Input placeholder="Field" />
            </Form.Item>
          ))}
          <Button onClick={() => add()}>Add Field</Button>
        </>
      )}
    </Form.List>
  </Collapse.Panel>
</Collapse>

References: https://ant.design/components/collapse#collapse (destroyInactivePanel)

Numeric Input Form Item Rules

For min and max validation, it must be always paired with type: 'number'

<Form.Item name="numeric_input" rules={[
  { required: true, type: 'number'  },
  { 
    type: 'number', // this must be added to work even tho already added above
    min: 0, 
    message: 'Minimum 0'
  },
  { 
    type: 'number', // this must be added to work
    min: 20000, 
    message: 'Minimum 0'
  },
]}>
  <SomeNumericInput>
</Form.Item>

On this page