Dawe
Dawe

Reputation: 610

ANTD dynamic form - initial values

I have issue with setting initial values for antd dynamic form. Is there any way how to init values in dynamic for. It requires registered field using getFieldDecorator. But for dynamic fields, that field is not registered before.

I am getting this error: You cannot set field before registering it.

code: https://codesandbox.io/s/jnx3p1nz5

import React from "react";
import { Select, Icon, Button, Form, Input } from "antd";

const FormItem = Form.Item;
const TextArea = Input.TextArea;
const Option = Select.Option;

const SELECT = ['opt1', 'opt2'];

class TestForm extends React.Component {
  state = {
    listKeys: [0]
  };

  componentDidMount() {
    const {
      form: { setFieldsValue }
    } = this.props;


    // WORK
    // setFieldsValue({
    //   name: 'test',
    // });

    // setFieldsValue({
    //   name: 'test',
    //   list: [
    //     {
    //       sub1: 'test1',
    //       sub2: 'test2',
    //     }
    //   ]
    // });

    // !!!!!!!!!!!! NOT WORK
    // setFieldsValue({
    //   name: 'test',
    //   list: [
    //     {
    //       sub1: 'test1',
    //       sub2: 'opt2'
    //     },
    //     {
    //       sub1: 'test11',
    //       sub2: 'opt1'
    //     }
    //   ]
    // });

    setFieldsValue({
      name: 'test',
      list: [
        {
          sub1: 'test1',
          sub2: 'opt2',
          opt2sub: 'bla',
        },
        {
          sub1: 'test11',
          sub2: 'opt1'
        },
        {
          sub1: 'test3',
          sub2: 'opt2',
          opt2sub: 'bla',
        },
      ]
    });
  }

  remove = k => {
    const { listKeys } = this.state;

    if (listKeys.length === 1) {
      return;
    }

    this.setState({
      listKeys: listKeys.filter(key => key !== k)
    });
  };

  add = () => {
    const { listKeys } = this.state;

    this.setState({
      listKeys: [...listKeys, listKeys.length]
    });
  };

  render() {
    const {
      form: { getFieldDecorator, getFieldValue }
    } = this.props;
    const { listKeys } = this.state;

    return (
      <Form onSubmit={this.handleSubmit}>
        <FormItem label="Name">
          {getFieldDecorator("name")(<Input placeholder="name" />)}
        </FormItem>
        {listKeys.map((key, index) => {
          const type = getFieldValue(`list[${key}].sub2`);

          return (
            <div key={key}>
              <FormItem label="Sub1">
                {getFieldDecorator(`list[${key}].sub1`)(
                  <Input placeholder="Sub1" />
                )}
              </FormItem>
              <FormItem label="Sub2">
                {getFieldDecorator(`list[${key}].sub2`,{
                  initialValue: 'opt1'
                })(
                  <Select>
                    {SELECT.map(item => <Option key={item} value={item}>{item}</Option> )}
                  </Select>
                )}
              </FormItem>
              {type === 'opt2' && (
                <FormItem label="opt2sub">
                  {getFieldDecorator(`list[${key}].opt2sub`)(
                    <Input placeholder="opt2sub" />
                  )}
                </FormItem>
              )}
              {index > 0 && (
                <Icon
                  className="dynamic-delete-button"
                  type="minus-circle-o"
                  onClick={() => this.remove(key)}
                />
              )}
            </div>
          );
        })}
        <FormItem>
          <Button type="dashed" onClick={this.add}>
            <Icon type="plus" />Add field
          </Button>
        </FormItem>
        <FormItem>
          <Button type="primary" htmlType="submit">
            Submit
          </Button>
        </FormItem>
      </Form>
    );
  }
}

export default Form.create()(TestForm);

Upvotes: 3

Views: 9294

Answers (2)

user4546364
user4546364

Reputation:

You can use forceRender={true} in the prop that holding the form to render it. I had a form inside drawer. For that i had same error. Which I used forceRender={true} in drawer prop. So whichever holding the form, you need to render that using forceRender.

Upvotes: 2

nkskalyan
nkskalyan

Reputation: 76

You should always register a field before you can use it. Here, I would suggest you to set the state with the list in componentDidMount and then use initialValue to set the value in render. For example

componentDidMount() {
  const {
    form: { setFieldsValue },
    listKeys,
  } = this.props;
  this.setState({listKeys})
}

render() {
  <FormItem label="Sub1">
    {getFieldDecorator(`list[${key}].sub1`, {initialValue: this.props.list[key].sub1})(
      <Input placeholder="Sub1" />
    )}
  </FormItem>
}

Upvotes: 0

Related Questions