How to use a select input type with redux-form?
Solution 1
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 option
s 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);
Solution 2
select rating example : redux-form
example how to handle selection in redux-form
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
/*------- connect react with redux --------*/
import { connect } from 'react-redux';
/*------- action which all data to data base --------*/
import { addProduct } from '../actions'
/*------- redux form --------*/
import { Field, reduxForm } from 'redux-form';
class Form extends Component {
//PRISTINE / DIRTY // TOUCHED / ERROR : events in redux-form
/*------- renderSelectField --------*/
renderSelectField(field){
const className = `form-input ${field.meta.touched && field.meta.error ? 'has-error':''}`;
return(
<div className={className}>
<label>{field.myLabel}</label>
<select {...field.input} >
{field.children}
</select>
<div className="error">
{field.meta.touched ? field.meta.error:''}
</div>
</div>
)
}
/*------- onSubmit() : runs on submit --------*/
onSubmit(values){
// const error = this.validate(values);
// console.log(error)
console.log(values)
this.props.dispatch(addProduct({
values
}))
}
render(){
return(
<div className="Form">
<div className="top">
<h3>Add a Message</h3>
<Link to="/">Back</Link>
</div>
<form onSubmit={this.props.handleSubmit((event)=>this.onSubmit(event))}>
<Field
myLabel="Select Rating"
name="rating"
component={this.renderSelectField}>
<option></option>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
<option value='4'>4</option>
<option value='5'>5</option>
</Field>
<button type="submit">Submit</button>
</form>
</div>
)
}
}
/*------- validate() : validates our form --------*/
function validate(values){
const errors = {};
if(!values.rating){
errors.rating = "The rating is empty"
}
return errors;
}
/*------- it returns messages when action is called and state going to change --------*/
function mapStateToProps(state){
return {
product: state.data
}
}
/*------- reduxForm : connects redux-form with react form --------*/
export default reduxForm({
validate,
form:'AddProduct',
})(
connect(mapStateToProps,{addProduct})(Form)
)
Clement Levesque
I am currently a Product Owner who tends to be a front-end developer. Hopefully I got skills from my studies... few years ago :)
Updated on July 18, 2022Comments
-
Clement Levesque almost 2 years
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);
-
Clement Levesque about 7 yearsThanks for your answer I will try it ! At the moment I am using the initiliaze function from redux-form to initialize my values (see my edited question). Do you know the difference between your solution and the initiliaze function ? What would you advice me to use ?
-
Deividas Karzinauskas about 7 years@ClementLevesque I am not sure where is your initialize function. It does not exist in the docs (redux-form.com/6.5.0/docs/api/ReduxForm.md) and
initialValues
is the method prescribed by official docs, so I would stick to that. -
Deividas Karzinauskas about 7 years@ClementLevesque I checked your edit - you should definitely use
initialValues
, becauseredux-form
will do all the work (less code to maintain). -
Clement Levesque about 7 yearsThanks for your help I will try with initialValues. For information I found the function is the doc : redux-form.com/6.0.5/docs/api/Props.md
-
Luca Bezerra over 6 yearsI couldn't quite make what you meant by 'does not have
option
s mapped', so I decided to add the blank option (<option></option>
), which causes the user to change the selection and thus the value is caught. Otherwise, if the user doesn't change values, it seems it won't get caught by my code. Writing it here in case it helps someone else.