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);
We will use the Redux Form onChange function so that the value emitted by React Select can be stored in our store by Redux Form. For onBlur, we want to set the value of the select to the input. value prop that Redux Form provides us. Now you have React Select's state being managed by Redux Form!
One solution is to use store. getState(). form[FORM_NAME].
The FieldArray component is how you render an array of fields. It works a lot like Field . With Field , you give a name , referring to the location of the field in the Redux state, and a component to render the field, which is given the props to connect the field to the Redux state.
formReducer has to be mounted on the Redux state at form . reduxForm() : The reduxForm() function is a higher-order component takes a configuration object and it always returns a new function. It is used to wrap the form component and bind user interaction to the Redux dispatch actions.
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);
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)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With