score:6

Accepted answer

if you're using antd version 4.9.0+, you can take advantage of the initialvalue property on the form.list. this allows you set intial values on the form items of the array. alternatively, you can set the initialvalues property on the form. here's a minimum viable example using the former method.

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 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 }) => (
            <>
              {fields.map((field) => (
                <space
                  key={field.key}
                  style={{ display: "flex", marginbottom: 8 }}
                  align="baseline"
                >
                  <form.item
                    {...field}
                    name={[field.name, "item_code"]}
                    fieldkey={[field.fieldkey, "item_code"]}
                  >
                    <input placeholder="item code" />
                  </form.item>
                  <form.item
                    {...field}
                    name={[field.name, "quantity"]}
                    fieldkey={[field.fieldkey, "quantity"]}
                  >
                    <input placeholder="quantity" />
                  </form.item>
                  <form.item
                    {...field}
                    name={[field.name, "special_requirements"]}
                    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

score:1

thanks to scratch'n'purr, i used your solution to further put the fields into an antd table.

first a short note: fieldkey={[field.fieldkey, "quantity"]} from the previous solution didn't work for me, but changing it to key={[field.key, "quantity"]}did the trick.

//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>
  );
};



Related Query

More Query from same tag