如何使用按钮道具动态禁用antd modal的按钮

How to dynamically disable the button of antd modal using button props

我有一个 antd Modal,我正在尝试验证一个字段并为其提供验证。我如何 enable/disable 基于验证的确定按钮。如果验证成功,则应启用按钮,否则禁用。

<Form>
    <Modal
      title={modalHeader}
      okText="ADD FIELD"
      cancelText="CANCEL"
      visible={visible}
      onCancel={onCancelHandler}
      onOk={() => onAddFieldHandler(fieldName)}
      width={600}
      okButtonProps={{disabled:true}}
    >
      <p>Please provide name</p>
      <Form.Item
      name="fieldName"
      rules={[{ required: true, message: 'Please enter name' }]}
      >
      <FieldNameInput
        placeholder="Field name..."
        value={fieldName}
        onChange={(event) => setFieldName(event.target.value)}

      />
      </Form.Item>
    </Modal>
    </Form>

您可以使用来自 Antd Forms API togehter with geFieldsError and the okButtonProps from Antd Modal APIonFieldsChange

  const [form] = Form.useForm();
  const [buttonDisabled, setButtonDisabled] = useState(true);
  return (
    <Modal
      ...
      okButtonProps={{ disabled:  buttonDisabled  }}
    >
     <Form
        form={form}
        ...
        onFieldsChange={() =>
          setButtonDisabled(
            form.getFieldsError().some((field) => field.errors.length > 0)
          )
        }
      >

这是一个有效的 Stackblitz

在 Modal 中包含表单,更新模式按钮状态的方法就是 运行 form instance's validateFields,但有两点需要考虑:

  1. 此函数是一个 Promise,因此状态必须在 await 之后更新验证结果。

  2. 我在使用 onFieldsChange 时遇到了一些循环问题(也许验证会触发某种字段更新)。相反,onValuesChange 对我来说已经足够好了。

  3. 运行 setTimeout 回调的验证似乎是强制性的。在没有 setTimeout returns 的情况下执行此操作会出现验证错误,即使所有字段都因 outOfDate: true 而有效。这似乎是因为 Antd Form 更新生命周期的工作方式,等到这个过程结束(我们可以用 setTimeout 轻松实现)解决这个问题。

验证成功 returns 表单值对象,验证失败 returns 包含错误列表的 errorInfo 对象,outOfDate 状态和当前表单值.你可以使用后者中的错误列表来获取Antd返回的验证消息,以显示更具描述性和具体的反馈。

最后,我的方法有这样的结构:

const MyModal = ({onFinish, ...otherProps}) => {
  const [canSubmit, setCanSubmit] = useState(false);
  const [form] = Form.useForm();

  return (
    <Modal
      {...otherProps}
      okButtonProps={{
          disabled: !canSubmit
      }}
    >
      <MyFormComponent
        form={form}
        onFinish={onFinish}
        onValuesChange={() => {
          setTimeout(() => {
            form
              .validateFields()
              .then(() => {
                  /*
                  values:
                    {
                      username: 'username',
                      password: 'password',
                    }
                */
                setCanSubmit(true);
              })
              .catch((err) => {
                /*
                errorInfo:
                  {
                    values: {
                      username: 'username',
                      password: 'password',
                    },
                    errorFields: [
                      { name: ['password'], errors: ['Please input your Password!'] },
                    ],
                    outOfDate: false,
                  }
                */
                setCanSubmit(false);
              });
          });
        }}
      />
    </Modal>
  );
};

在我的例子中,我有 Form inside modal 并且有 onFieldChange 道具,当​​你可以传递函数来执行一些操作时,由于 from 的变化,你可以这样:

const SomeModal = ({ visible }) => {
  const [form] = Form.useForm();
  const [buttonDisabled, setButtonDisabled] = useState(true);

  const handleOk = () => form.submit();

  const handleAfterClose = () => { 
    setButtonDisabled(true);
    form.resetFields();
  }

  const handleCancel = () => ...some action to hide modal;

  const handleFormFinish = (values) => {
    ... some logic here
  }

  return (
    <Modal
      title={"Some title..."}
      visible={visibile}
      onOk={handleOk}
      onCancel={handleCancel}
      afterClose={handleAfterClose}
      okButtonProps={{ disabled: buttonDisabled }}
    >
      <Form
        form={form}
        layout="vertical"
        name="acceptform"
        onFinish={handleFormFinish}
        initialValues={{
          ...initial values here
        }}
        onFieldsChange={() => {
          const actualFieldValues = form.getFieldsValue();
          const anyError = form.getFieldsError().some((field) => field.errors.length > 0);
          .. some logic if error etc..
          if (anyError) {
             setButtonDisabled(true);
          } 
          else {
             setButtonDisabled(false);
          }
      }}
    >

当然还需要在字段上设置一些验证器

<Form.Item
    label={"someLabel"}
    id="field"
    name="field"
    hasFeedback
    rules={[
    {
        type: "string",
        validator: async (rule, value) => inputFieldValidate(value, "custom message")
    },
  ]}
>

和验证器看起来很像:

const inputFieldValidate = async (value, message) => {
  if (someCondition)) {
    return Promise.reject(message);
  }
  return Promise.resolve();
};

这里有一些很高兴知道验证器是异步的,并且让它在没有任何警告的情况下工作只是处理承诺