0

I have an application where users can add their data in a form with 2 fields. They can add as many fields as they want.

const Demo = () => {
  const onFinish = values => {
    console.log("Received values of form:", values);
  };
  const firstDefaultOpen = {
    name: 0,
    key: 0,
    isListField: true,
    fieldKey: 0
  };
  const testHandler = a => {
    console.log("result", a.concat(firstDefaultOpen));
    return a.concat(firstDefaultOpen);
  };
  return (
    <Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
      <Form.List name="users">
        {(fields, { add, remove }) => {
          return (
            <div>
              {testHandler(fields).map(field => (
                <Space
                  key={field.key}
                  style={{ display: "flex", marginBottom: 8 }}
                  align="start"
                >
                  <Form.Item
                    {...field}
                    name={[field.name, "first"]}
                    fieldKey={[field.fieldKey, "first"]}
                    rules={[{ required: true, message: "Missing first name" }]}
                  >
                    <Input placeholder="First Name" />
                  </Form.Item>
                  <Form.Item
                    {...field}
                    name={[field.name, "last"]}
                    fieldKey={[field.fieldKey, "last"]}
                    rules={[{ required: true, message: "Missing last name" }]}
                  >
                    <Input placeholder="Last Name" />
                  </Form.Item>

                  <MinusCircleOutlined
                    onClick={() => {
                      remove(field.name);
                    }}
                  />
                </Space>
              ))}

              <Form.Item>
                <Button
                  type="dashed"
                  onClick={() => {
                    add();
                  }}
                  block
                >
                  <PlusOutlined /> Add field
                </Button>
              </Form.Item>
            </div>
          );
        }}
      </Form.List>

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

My target is to set a default pair of inputs as opened. Now you can see when you open the application that first name and last name inputs are open as default. This i made with:

 const firstDefaultOpen = {
    name: 0,
    key: 0,
    isListField: true,
    fieldKey: 0
  };
  const testHandler = a => {
    console.log("result", a.concat(firstDefaultOpen));
    return a.concat(firstDefaultOpen);
  };

and here i map() the new array:

 {testHandler(fields).map(field => (...

The issue is when i click on Add field button, because there when i try to write something in one input also the same text appears on the another. This is happening because when i click on Add field button you can see in the console.log("result", a.concat(firstDefaultOpen));, that 2 objects are with the same values like:

[Object, Object]
0: Object
name: 0
key: 0
isListField: true
fieldKey: 0
1: Object
name: 0
key: 0
isListField: true
fieldKey: 0

Question: How to set the first object with all values 0, and the next values to be higher, and to get something like?:

[Object, Object]
0: Object
name: 0
key: 0
isListField: true
fieldKey: 0
1: Object
name: 1
key: 1
isListField: true
fieldKey: 1
2: Object
name: 2
key: 2
isListField: true
fieldKey: 2
...

demo: https://codesandbox.io/s/hungry-star-nu5ld?file=/index.js:783-819

3 Answers 3

1

You can do this by just simply changing your firstDefaultOption from variable to function like this

    function firstDefaultOption(optionVal){
        return {
         name: optionVal,
         key: optionVal,
         isListField: optionVal,
         fieldKey: optionVal
     }
   }

and then changing your test handler like this

    const testHandler = a => {
    console.log("A",a)
    console.log("result", a.concat(firstDefaultOption(a.length)));
    return a.concat(firstDefaultOption(a.length));
  };
Sign up to request clarification or add additional context in comments.

2 Comments

i like your solution, i implemented in one of my application and when i upload an image, bellow appears suddenly another pair of inputs. Without your implementation it does not appears, do you see any issues? codesandbox.io/s/hungry-star-nu5ld?file=/index.js . I know that maybe this is additional question , but could you take a look please? It will be great if you will help,thanks.
what do you think about the issue?
0

Kind of a messy solution but it works... Comments added throughout

import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Form, Input, Button, Space } from "antd";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";

const Demo = () => {
  const onFinish = values => {
    console.log("Received values of form:", values);
  };
  const firstDefaultOpen = {
    //Set default to null
    name: null,
    key: null,
    isListField: true,
    fieldKey: null
  };
  const testHandler = a => {
    //Check for null and set first to 0
    if(firstDefaultOpen.name == null){
      firstDefaultOpen.name = 0;
      firstDefaultOpen.key = 0;
      firstDefaultOpen.fieldKey = 0;
    }
    //If not null.. then add 1 to each object item to make each unique
    else{
      firstDefaultOpen.name = firstDefaultOpen.name +1;
      firstDefaultOpen.key = firstDefaultOpen.key +1;
      firstDefaultOpen.fieldKey = firstDefaultOpen.fieldKey +1;
    }
    
    console.log("result", a.concat(firstDefaultOpen));
    return a.concat(firstDefaultOpen);
  };
  return (
    <Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
      <Form.List name="users">
        {(fields, { add, remove }) => {
          return (
            <div>
              {testHandler(fields).map(field => (
                <Space
                  key={field.key}
                  style={{ display: "flex", marginBottom: 8 }}
                  align="start"
                >
                  <Form.Item
                    {...field}
                    name={[field.name, "first"]}
                    fieldKey={[field.fieldKey, "first"]}
                    rules={[{ required: true, message: "Missing first name" }]}
                  >
                    <Input placeholder="First Name" />
                  </Form.Item>
                  <Form.Item
                    {...field}
                    name={[field.name, "last"]}
                    fieldKey={[field.fieldKey, "last"]}
                    rules={[{ required: true, message: "Missing last name" }]}
                  >
                    <Input placeholder="Last Name" />
                  </Form.Item>

                  <MinusCircleOutlined
                    onClick={() => {
                      remove(field.name);
                    }}
                  />
                </Space>
              ))}

              <Form.Item>
                <Button
                  type="dashed"
                  onClick={() => {
                    add();
                  }}
                  block
                >
                  <PlusOutlined /> Add field
                </Button>
              </Form.Item>
            </div>
          );
        }}
      </Form.List>

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

ReactDOM.render(<Demo />, document.getElementById("container"));

3 Comments

it does not work when i add many subfields. The text from fields is copied and in another input.
Everything seems fine on my end.. unless I'm reading your question wrong? Link------>codesandbox.io/s/hungry-star-nu5ld?file=/index.js
the issue is: when i fill the inputs with text and when i add the image, bellow appears another pair of inputs, but they should not appear.
0

You could declare the defaultOpen object with the let keyword and invoke an "update" function whenever you're ready to display an updated version, like:

let defaultOpen = getFirstDefaultOpen();
log(defaultOpen);

updateDefaultOpen(defaultOpen);
log(defaultOpen);

updateDefaultOpen(defaultOpen);
log(defaultOpen);

function updateDefaultOpen(currentState){
  currentState.name++;
  currentState.key++;
  currentState.fieldKey++;
}
function getFirstDefaultOpen(){
  return {
    name: 0,
    key: 0,
    isListField: true,
    fieldKey: 0
  }
}
function log(currentState){
  const output = Object.keys(currentState).reduce((str, key)=>{
    str += `${key}:${currentState[key]}, `;
    return str;
  },"");
  console.log(`{ ${output}}`);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.