antd Form.Item 只接受一个子项

发布于 2025-01-09 15:59:05 字数 905 浏览 1 评论 0原文

我创建了一个小小提琴来说明这个问题: https:// stackblitz.com/edit/react-avejvc-mmhqda?file=index.js

此表单有效:

      <Form initialValues={{ surname: 'Mouse'}}>
        <Form.Item name="surname">
          <Input />
        </Form.Item>
      </Form>

此表单无效:

      <Form initialValues={{ surname: 'Mouse'}}>
        <Form.Item name="surname">
          <Input />
          {null}
        </Form.Item>
      </Form>

唯一的区别是第二个中的 Form.Item形式有两个孩子。

这背后是否有意图?


如果有人想知道我为什么问。所以像这样的东西破坏了形式:

<Form.Item name={name}>
  {type==="string" && <Input />}
  {type==="integer" && <InputNumber />}
</Form.Item>

I've created a little Fiddle to illustrate the issue: https://stackblitz.com/edit/react-avejvc-mmhqda?file=index.js

This form works:

      <Form initialValues={{ surname: 'Mouse'}}>
        <Form.Item name="surname">
          <Input />
        </Form.Item>
      </Form>

This form doesn't:

      <Form initialValues={{ surname: 'Mouse'}}>
        <Form.Item name="surname">
          <Input />
          {null}
        </Form.Item>
      </Form>

The only difference is that the Form.Item in the second form has two children.

Is there an intention behind this?


In case anyone wonders why I am asking. So sth like this is breaking the form:

<Form.Item name={name}>
  {type==="string" && <Input />}
  {type==="integer" && <InputNumber />}
</Form.Item>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝戈者 2025-01-16 15:59:05

官方文档此处给出了在一个 Form.Item

<Form.Item label="Field">
    <Form.Item name="field" noStyle><Input /></Form.Item> // that will bind input
    <span>description</span>
</Form.Item>

您在 Form.Item 中放入的内容似乎有问题,即。可能不允许{null}

The official documentation here gives examples of using multiple children in one Form.Item.

<Form.Item label="Field">
    <Form.Item name="field" noStyle><Input /></Form.Item> // that will bind input
    <span>description</span>
</Form.Item>

You appear to have a problem with what you are putting in the Form.Item, ie. {null} may not be allowed.

丿*梦醉红颜 2025-01-16 15:59:05

我找到了解决方案,现在对发生的事情有了更好的了解。

从文档(https://ant.design/components/form/#Form.Item< /a>):

被Form.Item用name属性包裹后,value(或valuePropName定义的其他属性)onChange(或trigger定义的其他属性)props将被添加到表单控件中,表单数据的流动将由 Form 处理

有一个文档中的工作示例也是如此,这里是codepen: https://codepen.io/pen? &编辑=001

const {  useState  } = React;;
const {  Form, Input, Select, Button  } = antd;
const { Option } = Select;

const PriceInput = ({ value = {}, onChange }) => {
  const [number, setNumber] = useState(0);
  const [currency, setCurrency] = useState('rmb');

  const triggerChange = (changedValue) => {
    onChange?.({
      number,
      currency,
      ...value,
      ...changedValue,
    });
  };

  const onNumberChange = (e) => {
    const newNumber = parseInt(e.target.value || '0', 10);

    if (Number.isNaN(number)) {
      return;
    }

    if (!('number' in value)) {
      setNumber(newNumber);
    }

    triggerChange({
      number: newNumber,
    });
  };

  const onCurrencyChange = (newCurrency) => {
    if (!('currency' in value)) {
      setCurrency(newCurrency);
    }

    triggerChange({
      currency: newCurrency,
    });
  };

  return (
    <span>
      <Input
        type="text"
        value={value.number || number}
        onChange={onNumberChange}
        style={{
          width: 100,
        }}
      />
      <Select
        value={value.currency || currency}
        style={{
          width: 80,
          margin: '0 8px',
        }}
        onChange={onCurrencyChange}
      >
        <Option value="rmb">RMB</Option>
        <Option value="dollar">Dollar</Option>
      </Select>
    </span>
  );
};

const Demo = () => {
  const onFinish = (values) => {
    console.log('Received values from form: ', values);
  };

  const checkPrice = (_, value) => {
    if (value.number > 0) {
      return Promise.resolve();
    }

    return Promise.reject(new Error('Price must be greater than zero!'));
  };

  return (
    <Form
      name="customized_form_controls"
      layout="inline"
      onFinish={onFinish}
      initialValues={{
        price: {
          number: 0,
          currency: 'rmb',
        },
      }}
    >
      <Form.Item
        name="price"
        label="Price"
        rules={[
          {
            validator: checkPrice,
          },
        ]}
      >
        <PriceInput />
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form.Item>
    </Form>
  );
};

ReactDOM.render(<Demo />, mountNode);

I found a solution and have a better understanding now of what is going on.

From the docs (https://ant.design/components/form/#Form.Item):

After wrapped by Form.Item with name property, value(or other property defined by valuePropName) onChange(or other property defined by trigger) props will be added to form controls, the flow of form data will be handled by Form

There is a working example in the docs too, here is the codepen: https://codepen.io/pen?&editors=001

const {  useState  } = React;;
const {  Form, Input, Select, Button  } = antd;
const { Option } = Select;

const PriceInput = ({ value = {}, onChange }) => {
  const [number, setNumber] = useState(0);
  const [currency, setCurrency] = useState('rmb');

  const triggerChange = (changedValue) => {
    onChange?.({
      number,
      currency,
      ...value,
      ...changedValue,
    });
  };

  const onNumberChange = (e) => {
    const newNumber = parseInt(e.target.value || '0', 10);

    if (Number.isNaN(number)) {
      return;
    }

    if (!('number' in value)) {
      setNumber(newNumber);
    }

    triggerChange({
      number: newNumber,
    });
  };

  const onCurrencyChange = (newCurrency) => {
    if (!('currency' in value)) {
      setCurrency(newCurrency);
    }

    triggerChange({
      currency: newCurrency,
    });
  };

  return (
    <span>
      <Input
        type="text"
        value={value.number || number}
        onChange={onNumberChange}
        style={{
          width: 100,
        }}
      />
      <Select
        value={value.currency || currency}
        style={{
          width: 80,
          margin: '0 8px',
        }}
        onChange={onCurrencyChange}
      >
        <Option value="rmb">RMB</Option>
        <Option value="dollar">Dollar</Option>
      </Select>
    </span>
  );
};

const Demo = () => {
  const onFinish = (values) => {
    console.log('Received values from form: ', values);
  };

  const checkPrice = (_, value) => {
    if (value.number > 0) {
      return Promise.resolve();
    }

    return Promise.reject(new Error('Price must be greater than zero!'));
  };

  return (
    <Form
      name="customized_form_controls"
      layout="inline"
      onFinish={onFinish}
      initialValues={{
        price: {
          number: 0,
          currency: 'rmb',
        },
      }}
    >
      <Form.Item
        name="price"
        label="Price"
        rules={[
          {
            validator: checkPrice,
          },
        ]}
      >
        <PriceInput />
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form.Item>
    </Form>
  );
};

ReactDOM.render(<Demo />, mountNode);

邮友 2025-01-16 15:59:05

将元素包装在 内可以很好地适应上述场景。检查下面的代码

<Form.Item label="Role">
  <Input.Group compact>
    {error?.type === "getRulesError" && (
      <Alert message="Error fetching roles" type="error" showIcon />
    )}
    {!error?.type && rolesLoading && <Loading />}
    {!error?.type && !rolesLoading && (
      <Form.Item
        name="role"
        rules={[
          {
            required: true,
            message: "Please select user role"
          }
        ]}
        noStyle
      >
        <Select
          placeholder="Select user role"
          style={{ width: "100%" }}
        >
          {roles?.map(each => (
            <Option value={each.roleName} key={each.roleId}>
              {each?.roleName}
            </Option>
          ))}
        </Select>
      </Form.Item>
    )}
  </Input.Group>
</Form.Item>

Wrapping elements inside <Input.Group> works fine with above scenario. Check below code

<Form.Item label="Role">
  <Input.Group compact>
    {error?.type === "getRulesError" && (
      <Alert message="Error fetching roles" type="error" showIcon />
    )}
    {!error?.type && rolesLoading && <Loading />}
    {!error?.type && !rolesLoading && (
      <Form.Item
        name="role"
        rules={[
          {
            required: true,
            message: "Please select user role"
          }
        ]}
        noStyle
      >
        <Select
          placeholder="Select user role"
          style={{ width: "100%" }}
        >
          {roles?.map(each => (
            <Option value={each.roleName} key={each.roleId}>
              {each?.roleName}
            </Option>
          ))}
        </Select>
      </Form.Item>
    )}
  </Input.Group>
</Form.Item>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文