How to use a select input type with redux-form?

Clement Levesque picture Clement Levesque · Mar 12, 2017 · Viewed 18.7k times · Source

I searched and tried a lot to use a select input type with my react form using redux-form library.

Everything works, all other input types are ok, but not the select one for the following actions : initialize, retrieve the value submitted etc.

I tried to use the model prop with "select" and with my own function to render it. When I use the select version for model, I manage to get the options of the combobox field but I don't manage to set a value and retrieve it when I submit. With my own function I don't even manage to set the options to the list...

Here is my code :

// FormComponent file
const { handleSubmit } = this.props;
...
<form onSubmit={handleSubmit(this.props.onSubmitProfileUpdate)}>
    <Field name='ranking' className='input-row form-group form-control' component={renderSelectField}>
                        {tennisRankings.map(ranking =>
                          <option value={ranking} key={ranking}>{ranking}</option>
                        )}
                      </Field>
...
ProfileForm.propTypes = {
  user: React.PropTypes.object,
  fields: React.PropTypes.shape({
    firstname: React.PropTypes.string,
    lastname: React.PropTypes.string,
    ranking: React.PropTypes.string,
    email: React.PropTypes.string,
    telephone: React.PropTypes.string,
    city: React.PropTypes.string
  }),
  errorMessage: React.PropTypes.string,
  confirmationMessage: React.PropTypes.string,
  onSubmitProfileUpdate: React.PropTypes.func.isRequired,
  handleSubmit: propTypes.handleSubmit,
  initialize: propTypes.initialize
};

export default reduxForm({
  form: 'profile',
  validate: validateProfileForm
})(ProfileForm);

My function to render the field :

// Functions shared
export const renderSelectField = (field) => {
  var styles = {};
  var containerStyle = getInputStylesContainer();

      if (field.input.value || field.meta.touched) {
        if (!field.meta.error) {
          styles = getInputStylesSuccess();
          containerStyle = classNames(containerStyle, {'has-success': true});
        } else {
          styles = getInputStylesError();
          containerStyle = classNames(containerStyle, {'has-error': true});
        }
      }

      return (<div className={containerStyle}>
        {displayInputLabel(styles.idInput, field.label)}
        <select {...field.input} className='form-control' id={styles.idInput} value={field.input.value} type={field.type} placeholder={field.label} aria-describedby={styles.ariaDescribedBy} />
        <span className={styles.glyphicon} aria-hidden='true' />
        {field.meta.touched && field.meta.error &&
        displayErrorMessage(field.meta.error)}
      </div>);
    };

Do you have any clue to perform that simple action ? Be indulgent I am a beginner :)

Thanks a lot for your help :)

EDIT :

Here is the way that I am initializing my form values :

// FormComponent file
handleInitialize () {
    // TODO: Manage properly user not available case (redux form reason ?)
    if (this.props.user.firstname === undefined) return;
    const initData = {
      'firstname': this.props.user.firstname.toString(),
      'lastname': this.props.user.lastname.toString(),
      'city': this.props.user.city === undefined ? '' : this.props.user.city.toString(),
      'email': this.props.user.email.toString(),
      'ranking': this.props.user.ranking.toString(),
      'telephone': this.props.user.telephone === undefined ? '' : this.props.user.telephone.toString()
    };
    console.log('Ranking', this.props.user.ranking);
    this.props.initialize(initData);
  }

  componentDidMount () {
    this.handleInitialize();
  }

....

export default reduxForm({
  form: 'profile',
  validate: validateProfileForm
})(ProfileForm);

Answer

Deividas Karzinauskas picture Deividas Karzinauskas · Mar 13, 2017

Here's an example of a simple select field from the official docs:

<div>
  <label>Favorite Color</label>
  <div>
    <Field name="favoriteColor" component="select">
      <option></option>
      <option value="ff0000">Red</option>
      <option value="00ff00">Green</option>
      <option value="0000ff">Blue</option>
    </Field>
  </div>
</div>

Your implementation does not have options mapped, so select does not work.

Sidenote To pass initial values you should add initialValues property to your reduxForm configuration instead of adding value attribute to the field. Example below:

export default reduxForm({
  form: 'profile',
  validate: validateProfileForm,
  initialValues: { ... }
})(ProfileForm);