reactjs 如何在React with ANTd中创建动态表单输入字段

1tu0hz3e  于 2022-12-12  发布在  React
关注(0)|答案(2)|浏览(227)

代码沙箱链接:https://codesandbox.io/s/compassionate-sanderson-1m8nv?file=/src/App.js
我在这个题目上找不到太多资料,以下是我想达到的目标:
我希望用户能够编辑数据库中已经存在的采购订单的一些详细信息,然后使用表单重新提交采购订单。原始采购订单的详细信息应该显示在表单输入字段中,用户可以通过这些字段直接更改它们,然后提交。
我不精通网页开发,所以请耐心等待。
我希望最终的表单对象如下所示:

{
    po_number:"123abc",
    carrier:"Fastway",
    items: [{
                item_code:"dnh75n",
                quantity:"10",
                special_requirements:"Add picture of happy dog"
            },
            {
                item_code:"456def",
                quantity:"4",
                special_requirements:"Do not include lids"
            }
        ]
}

生成的表单输入字段的数量将取决于采购订单中的项目数量。我在下面创建了一个简单的React组件来演示我正在尝试做什么。或者只是 checkout 上面的代码沙箱链接。任何帮助都将不胜感激。我甚至找不到关于如何对ANTd表单项目进行分组以创建采购订单中项目数组的信息。我'我在他们的网站上看到了很多动态表单的例子,但是我想根据采购订单中预先存在的项目来创建表单,而不是用用户输入来添加字段。

import { Form, Input, Button } from 'antd';

//This is the order that already exists
const order = {
    po_number:"123abc",
    carrier:"Fastway",
    items: [{
                item_code:"dnh75n",
                quantity:"10",
                special_requirements:"Add picture of happy dog"
            },
            {
                item_code:"456def",
                quantity:"4",
                special_requirements:"Do not include lids"
            }
        ]
};

const GroupForm = () => {

    const onFinish = values => {
        console.log(values);
    }
    

    //Create form fields based off how many items are in the order
    const itemInputs = order.items.map(item => {
        return (
            <div>
                <b>Item{" " + item.item_code}</b>
                <Form.Item name={item.item_code + "_quantity"} label="quantity">
                    <Input defaultValue={item.quantity} style={{width: "500px"}} />
                </Form.Item>

                <Form.Item name={item.item_code + "_requirements"} label="speacial requirements">
                    <Input defaultValue={item.special_requirements}  style={{width: "500px"}} />
                </Form.Item>
            </div>
        );
    });

    return(
        <div>
            <Form onFinish={onFinish}>
                <b>{"Order " + order.po_number}</b>
                
                <Form.Item name="carrier" label="carrier">
                    <Input defaultValue={order.carrier} style={{width: "500px"}} />
                </Form.Item>

                <b>Order Items</b>

                {itemInputs}

                <Form.Item>
                    <Button type="primary" htmlType="submit"> Change Details </Button>
                </Form.Item>
            </Form>
        </div>
    );
}

export default GroupForm;
6jygbczu

6jygbczu1#

如果你使用的是antd 4.9.0以上的版本,你可以利用Form.ListinitialValue属性。这允许你在数组的表单项上设置初始值。或者,你可以在Form上设置initialValues属性。下面是一个使用前一种方法的最简单可行的例子。

import { Form, Input, Button, Space } from "antd";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import React from "react";

//Basic Idea
/* 
    I want the user to be able to edit some details of a purchase order that already exists in the database,
    then resubmit the order with a form.
    The details of the purchase order should be orginally displayed in the form input fields,
    and the user can change them directly via those fields. 
*/

//This is the order that already exists
const order = {
  po_number: "123abc",
  carrier: "Fastway",
  items: [
    {
      item_code: "dnh75n",
      quantity: "10",
      special_requirements: "Add picture of happy dog"
    },
    {
      item_code: "456def",
      quantity: "4",
      special_requirements: "Do not include lids"
    }
  ]
};

const itemInputs = order.items

const GroupForm = () => {
  const onFinish = (values) => {
    console.log(values);
  };

  /**
   * Edited: `const itemInputs = order.items` above
   */
  //Create form fields based off how many items are in the order
  // const itemInputs = order.items.map((item) => {
  //   return {
  //     item_code: item.item_code,
  //     quantity: item.quantity,
  //     special_requirements: item.special_requirements
  //   };
  // });

  return (
    <div>
      <Form onFinish={onFinish}>
        <b>{"Order " + order.po_number}</b>

        <Form.Item name="carrier" label="carrier" initialValue={order.carrier}>
          <Input style={{ width: "500px" }} />
        </Form.Item>
        <Form.Item
          name="po_number"
          label="PO number"
          initialValue={order.po_number}
          hidden
        >
          <Input />
        </Form.Item>

        <b>Order Items</b>

        <Form.List name="items" initialValue={itemInputs}>
          {(fields, { add, remove }) => (
            <>
              {fields.map((field) => (
                <Space
                  key={field.key}
                  style={{ display: "flex", marginBottom: 8 }}
                  align="baseline"
                >
                  <Form.Item
                    {...field}
                    name={[field.name, "item_code"]}
                    // no need anymore
                    // fieldKey={[field.fieldKey, "item_code"]}
                  >
                    <Input placeholder="Item Code" />
                  </Form.Item>
                  <Form.Item
                    {...field}
                    name={[field.name, "quantity"]}
                    // no need anymore
                    // fieldKey={[field.fieldKey, "quantity"]}
                  >
                    <Input placeholder="Quantity" />
                  </Form.Item>
                  <Form.Item
                    {...field}
                    name={[field.name, "special_requirements"]}
                    // no need anymore
                    // fieldKey={[field.fieldKey, "special_requirements"]}
                  >
                    <Input placeholder="Quantity" />
                  </Form.Item>
                  <MinusCircleOutlined onClick={() => remove(field.name)} />
                </Space>
              ))}
              <Form.Item>
                <Button
                  type="dashed"
                  onClick={add}
                  block
                  icon={<PlusOutlined />}
                >
                  Add item
                </Button>
              </Form.Item>
            </>
          )}
        </Form.List>

        <Form.Item>
          <Button type="primary" htmlType="submit">
            {" "}
            Change Details{" "}
          </Button>
        </Form.Item>
      </Form>
    </div>
  );
};

export default GroupForm;

// I want to submit a form object that looks like this. E.g.
// This is what 'onFinish' should display in the console
/*

{
    po_number:"123abc",
    carrier:"Fastway",
    items: [{
                item_code:"dnh75n",
                quantity:"10",
                special_requirements:"Add picture of happy dog"
            },
            {
                item_code:"456def",
                quantity:"4",
                special_requirements:"Do not include lids"
            }
        ]
}

*/

DEMO

uinbv5nw

uinbv5nw2#

感谢Scratch'N'Purr,我使用您的解决方案进一步将字段放入antd表中。
先简短说明一下:以前的解决方案中的fieldKey={[field.fieldKey, "quantity"]}对我不起作用,但将其更改为key={[field.key, "quantity"]}就起了作用。

//define the columns for the table
const columns = [
    {
      title: "ITEM#",
      dataIndex: "item_code",
      key: "item_code",
      width: "12%",
      //use the field here to get all infos for the form
      render: (_, field) => (
        <Form.Item
          {...field}
          name={[field.name, "item_code"]}
          key={[field.key, "item_code"]}
          noStyle
        >
          <Input placeholder="ITEM#" />
        </Form.Item>
      ),
    },
    {
      title: "Quantity",
      dataIndex: "quantity",
      key: "quantity",
      render: (_, field) => (
        <Form.Item
          {...field}
          name={[field.name, "quantity"]}
          //@ts-ignore
          key={[field.key, "quantity"]}
          noStyle
        >
          <Input placeholder="Quantity" />
        </Form.Item>
      ),
}];

const GroupForm = () => {
  const onFinish = (values) => {
    console.log(values);
  };

  //Create form fields based off how many items are in the order
  const itemInputs = order.items.map((item) => {
    return {
      item_code: item.item_code,
      quantity: item.quantity,
      special_requirements: item.special_requirements,
    };
  });

  return (
    <div>
      <Form onFinish={onFinish}>
        <b>{"Order " + order.po_number}</b>
        <Form.Item name="carrier" label="carrier" initialValue={order.carrier}>
          <Input style={{ width: "500px" }} />
        </Form.Item>
        <Form.Item
          name="po_number"
          label="PO number"
          initialValue={order.po_number}
          hidden
        >
          <Input />
        </Form.Item>

        <b>Order Items</b>

        <Form.List name="items" initialValue={itemInputs}>
          {(fields, { add, remove }, { errors }) => (
            <>
              {/* This is where to put the table. As a data source i used the fields */}
              <Table dataSource={fields} columns={columns} pagination={false} />
              <Form.Item>
                <Button
                  type="dashed"
                  onClick={() => add()}
                  style={{ width: "60%" }}
                  icon={<PlusOutlined />}
                >
                  Add field
                </Button>
                <Form.ErrorList errors={errors} />
              </Form.Item>
            </>
          )}
        </Form.List>

        <Form.Item>
          <Button type="primary" htmlType="submit">
            {" "}
            Change Details{" "}
          </Button>
        </Form.Item>
      </Form>
    </div>
  );
};

相关问题