Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redux-form: <FieldArray> + <FormSection> for complex arrays of objects

I'm using redux-form to try to create a form that results in an array of objects, such as:

const formData = {
  //...
  rules: [
    {
      level: 1,
      source: 'some source',
      //...
    }, {
      level: 3,
      source: 'another source'
      //...
    }
  ]
}

It seems like I should be able to next multiple FormSections with a FieldArray component...but I can't make it work. Here's my current attempt:

const renderRules = ({ fields, meta: { error } }) => (
  <div>
    <Button
      text="Add Rule"
      onClick={e => {
        e.preventDefault()
        fields.push()
      }}
    />
    {fields.map((rule, index) => (
      <FormSection name="rule"} key={index}>
        <legend>Rule {index + 1}</legend>
        <Field name="level" component={Select} label="Level">
            <Option value={1}>Level 1</Option>
            <Option value={2}>Level 2</Option>
            <Option value={3}>Level 3</Option>
        </Field>
        <Field name="source" component={Input} label="Source" />
      </FormSection>
    ))}
  </div>
)

but this does not work :( as all the values get put under the rule key, not as an object within the rules array. Has anyone done this before? All the examples I can find of FieldArray only use a single Field element, but it's got to be possible to do something more complex. Has anyone done this before? Any help is appreciated! Thanks.

like image 547
axelav Avatar asked Feb 08 '18 21:02

axelav


1 Answers

Figured it out & am posting for anyone else who comes up against this issue. Don't use a FormSection & use the rule argument when assigning the name of each field within the array, like so:

const renderRules = ({ fields, meta: { error } }) => (
  <div>
    <Button
      text="Add Rule"
      onClick={e => {
        e.preventDefault()
        fields.push()
      }}
    />
    {fields.map((rule, index) => (
      <legend>Rule {index + 1}</legend>
      <Field name={`${rule}.level`} component={Select} label="Level">
          <Option value={1}>Level 1</Option>
          <Option value={2}>Level 2</Option>
          <Option value={3}>Level 3</Option>
      </Field>
      <Field name={`${rule}.source`} component={Input} label="Source" />
    ))}
  </div>
)

This gives the Field a name of rule[0].limit or rule[0].source & correctly nests the object within the array.

like image 136
axelav Avatar answered Sep 30 '22 14:09

axelav