⚠️ This lesson is retired and might contain outdated information.

Use FieldArray to deal with multiple similar fields

Rory Smith
InstructorRory Smith
Share this video with your friends

Social Share Links

Send Tweet
Published 7 years ago
Updated 2 years ago

There can be situations in which the user needs to add or remove fields from a form depending on the amount of fields they need to fill out. Using redux-form, we can use the built-in FieldArray component to easily deal with this situation.

Instructor: [00:00] Here we have a form containing some text fields, a select field and a check box. Let's add a section which allows the user to add and remove discount codes. There could be any number of discount codes.

[00:16] We'll head over to fields/index.js where the rest of our fields live. We're going to write a new stateless component called discounts. It's going to have fields as its prop. It's going to return div with the class name, custom field array container.

[00:44] Then we're going to map over the fields in our props. Code will correspond to the discount code and we'll return a div using the index as the key and the class name field array item.

[01:03] Now we're going to use redux forms field component. Let's go ahead and import that. We'll create a new field. The name can be the code. Its type is text. The components it uses is the custom input component which is up here, and we'll provide a label which will be discount code with the index.

[01:35] For each of these fields we'll add a button which allows us to delete a discount code. To do that we'll just provide an onclick method in passing a function, and we can return fields.remove passing in the index. The remove method is provided to us by a redux form as the button's text. We'll use a cross sign.

[02:05] Now we need to provide a button that allows us to add discount codes. This time we provide an onclick method, and we just need to say fields.push. The text will depend on how many discount codes are already rendered.

[02:28] We can say if there are no fields add the discount codes, otherwise add another. Let's provide auto focus so that the field order fixes as soon as it renders on the page. Because we're passing that into our custom input, we need to be explicit about the auto focus.

[02:50] On our input field we can say auto focus equals props.autofocus. Now let's hook this up to our register form, and at the bottom we're going to add field array, put the name discount codes, and the component is discounts.

[03:13] We'll need to import field array from redux form and discounts from the function we just wrote. Field array from redux form and discounts from fields. Lastly, let's open our CSS file, and we'll add some CSS for the field array items. They're going to be display flex and justify content space between.

[03:43] The field array item button can have align self start. Let's save and refresh now. Here's the add discount codes button. Let's provide some spacing to it by heading to the selector for custom input container and custom select container, and we'll add custom field array container.

[04:14] Here's the spacing. When we click on it, we have this new field appear. Now we can add some discount codes. Let's ensure that they get attached to our form data correctly. We'll provide some values for the required fields, and we'll hit submit.

[04:39] Here are form values so the discount codes array contains one of our codes along with the rest of the data. If we want to, we can delete these fields from our form.

Justin Noel
Justin Noel
~ 6 years ago

If the user taps the button to add a discount code, you can make the discount code required by adding validate={[required]} to the definition of the Field.

export const discounts = ({ fields }) => (
  <div className="custom-field-array-container">
    {fields.map((code, index) => (
      <div key={index} className="field-array-item">
        <Field
          name={code}
          type="text"
          component={customInput}
          label={`Discount Code #${index + 1}`}
          autoFocus
          validate={[required]}
        />
        <button type="button" onClick={() => fields.remove(index)}>
          &times;
        </button>
      </div>
    ))}
    <button type="button" onClick={() => fields.push()}>
      Add {!fields.length ? 'Discount Code(s)' : 'Another'}
    </button>
  </div>
);

Justin Noel
Justin Noel
~ 6 years ago

How can you pre-populate or initialize the fields based on existing discount codes? For example, in RegisterForm.js, how can you pass down to the component some existing values?

I'm looking for something like this:

<FieldArray name="discountCodes" component={discounts} fields={ this.state.discountCodoes }/>
Rory Smith
Rory Smithinstructor
~ 6 years ago

How can you pre-populate or initialize the fields based on existing discount codes?

Hi Justin, you can do this with this.props.initialize inside a redux-form component. Try adding this:

  componentWillMount() {
    this.props.initialize({ discountCodes: ['hello', 'world'] })
  }
Justin Noel
Justin Noel
~ 6 years ago

Thanks Rory. That did the trick. Here's a working sample:

https://codesandbox.io/s/3x7p6pz0jq

I've got another question/concern about FieldArray's but I'll post it after I get a good working sample.

Justin Noel
Justin Noel
~ 6 years ago

Okay Rory, here is my sample:

https://codesandbox.io/s/q3rxn5oj76 (See RegisterForm.js to see what I'm trying to do.

In my project, I can't have the "add more discount codes" button within the component that generates the fields. It has to be external to the FieldArray due to design layout issues.

So, how can I have an external button that triggers pushing onto the fields array?

Justin Noel
Justin Noel
~ 6 years ago

Rory,

I finally found a solution for this via StackOverflow: https://stackoverflow.com/a/41607591/75644

When I get a chance, I'll update my sample above to include the fix for this.

Justin Noel
Justin Noel
~ 6 years ago

Here's my solution to this problem:

https://calendee.com/2018/09/22/adding-to-redux-form-fieldarray/

Markdown supported.
Become a member to join the discussionEnroll Today