5

I'm trying to figure out how to use this.props.dispatch(change) in order use one field selector value to update another fields value within a FieldArray.

https://codesandbox.io/s/2p7k7jn930

I can't seem to get the syntax in this correct.

this.props.dispatch(
        change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
      );

Any thoughts? Expected behavior would be to add a member and then have anything typed into the Last Name field be programmatically updated in the First Name field.

/**
The following can replace the file in the Field Arrays example
(https://github.com/erikras/redux-form/tree/master/examples/fieldArrays) to demonstrate this functionality.
**/
import React from "react";
import { connect } from "react-redux";
import {
  Field,
  FieldArray,
  reduxForm,
  formValueSelector,
  change
} from "redux-form";
import validate from "./validate";

const selector = formValueSelector("fieldArrays");

const renderField = ({ input, label, type, meta: { touched, error } }) => (
  <div>
    <label>{label}</label>
    <div>
      <input {...input} type={type} placeholder={label} />
      {touched && error && <span>{error}</span>}
    </div>
  </div>
);

class Member extends React.Component {
  componentDidUpdate(prevProps, props) {
    if (this.props.hasLastName !== prevProps.hasLastName) {
      this.props.dispatch(
        change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
      );
    }
  }

  render() {
    const { member, index, fields, hasLastName } = this.props;
    return (
      <li key={index}>
        <button
          type="button"
          title="Remove Member"
          onClick={() => fields.remove(index)}
        />
        <h4>Member #{index + 1}</h4>
        <Field
          name={`${member}.firstName`}
          type="text"
          component={renderField}
          label="First Name"
        />
        <Field
          name={`${member}.lastName`}
          type="text"
          component={renderField}
          label="Last Name"
        />
        {hasLastName && <p>{hasLastName}</p>}
      </li>
    );
  }
}
Member = connect((state, props) => ({
  hasLastName: selector(state, `${props.member}.lastName`)
}))(Member);

const renderMembers = ({ fields, meta: { touched, error } }) => (
  <ul>
    <li>
      <button type="button" onClick={() => fields.push({})}>
        Add Member
      </button>
      {touched && error && <span>{error}</span>}
    </li>
    {fields.map((member, index) => (
      <Member member={member} fields={fields} index={index} key={index} />
    ))}
  </ul>
);

const FieldArraysForm = props => {
  const { handleSubmit, pristine, reset, submitting } = props;
  return (
    <form onSubmit={handleSubmit}>
      <Field
        name="clubName"
        type="text"
        component={renderField}
        label="Club Name"
      />
      <FieldArray name="members" component={renderMembers} />
      <div>
        <button type="submit" disabled={submitting}>
          Submit
        </button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  );
};

export default reduxForm({
  form: "fieldArrays", // a unique identifier for this form
  validate
})(FieldArraysForm);

3 Answers 3

6

In order to access the FieldArray dynamically, you would want to change this:

change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)

to this:

change("FieldArraysForm", `members[${this.props.index}].firstName`, this.props.hasLastName)

Also, pass in the form selector specified:

const selector = formValueSelector("fieldArrays");

This would give you:

change("fieldArrays", `members[${this.props.index}].firstName`, this.props.hasLastName)

Had to get some help on this one - thanks goes to @Amanda Field.

Sign up to request clarification or add additional context in comments.

Comments

5

You need to specify the index of the field in FieldArray you want to change. To do so, just use <fieldName>.<index>.<propertyName>, for instance:

this.props.change('members.0.firstName', 'Donald')

where member is the name of your FieldArray field, 0 is the index of the item in the array you want to change and firstName is the property of the object. See sandbox here

2 Comments

Thanks for the response! Sorry I should have mentioned that I was already able to make it work by hard coding the value. I'm wondering how to make it dynamic.... So if for instance there are 4 field arrays created how would I handle dynamically making the selectors and adding the change dispatches accordingly.
Any thoughts on this @Dario right now its become a bit of a show stopper for us?
0

It can be updated using splice:

fields.splice(index, 1, { ...fields.get(index), firstName: hasLastName })

1 means replace item.

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.