ReactJS: How to wrap react-select in redux-form field? - reactjs

I am working on react-select library and facing some issues, I am using redux-form library and importing <Field /> component from it. So that I can submit the values via form to service.
Below mentioned code works fine, when I use default <Select> from react-select. I can able to select the values from the drop down and the value will be selected even on focus out the value will remain. But selected value is not submitting via form due to redux-form that's why I am wrapping <Select /> component and using with <Field name="sample" component={RenderSelectInput} id="sampleEX" options={options} />
import React from 'react';
import Select from 'react-select';
import RenderSelectInput from './RenderSelectInput'; // my customize select box
var options = [{ value: 'one', label: 'One' }, { value: 'two', label: 'Two' }];
class SelectEx extends React.Component {
constructor() {
super();
this.state = { selectValue: 'sample' }
this.updateValue = this.updateValue.bind(this);
}
updateValue(newValue) {
this.setState({ selectValue: newValue })
}
render() {
return (
<div>
<Select name="select1" id="selectBox" value={this.state.selectValue} options={options} onChange={this.updateValue}/>
//This works but value won't submit ...
<Field name="sample" component={RenderSelectInput} id="sampleEX" options={options} />
//For this, selected value vanishes once I come out of component.
</div>
)
}
}
export default SelectEx;
But when I use with my customized select (I am wrapping the to submit the value from form) the <Select> component can be visible in UI even the values also. But unable to select the value from dropdown ..., If I select also it displays in the <Select> box but on focus out it vanishes. Please help me ...
RenderSelectInput component:
import React from 'react';
import {Field, reduxForm} from 'redux-form';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
const RenderSelectInput = ({input, options, name, id}) => (
<div>
<Select {...input} name={name} options={options} id={id} />
</div>
)
export default RenderSelectInput;

When using react-select with redux-form, you'll need to change the default behavior of onChange and onBlur method and call redux-form's onChange and onBlur method respectively.
So, Try this:
const RenderSelectInput = ({input, options, name, id}) => (
<Select
{...input}
id={id}
name={name}
options={options}
value={input.value}
onChange={(value) => input.onChange(value)}
onBlur={(value) => input.onBlur(value)}
/>
)
and use the above component like
<Field component={RenderSelectInput} />
Calling redux-form's onBlur method when focus is removed from the Select field will prevent loss of value.

Here this worked for me,
import React, { Component } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
export default class RenderSelectInput extends Component {
onChange(event) {
if (this.props.input.onChange && event != null) {
this.props.input.onChange(event.value);
} else {
this.props.input.onChange(null);
}
}
render() {
const { input, options, name, id, ...custom } = this.props;
return (
<Select
{...input}
{...custom}
id={id}
name={name}
options={options}
value={this.props.input.value || ''}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
onChange={this.onChange.bind(this)}
/>
);
}
}
this was extracted from here: https://ashiknesin.com/blog/use-react-select-within-redux-form/

Use this which works perfectly and it also handles redux form validation.
import React, {Component} from 'react';
import Select from 'react-select';
import {FormGroup} from "reactstrap";
class CustomSelect extends Component {
render() {
const {meta: {touched, error}} = this.props;
const className = ` form-group mb-3 ${touched && error ? 'has-danger' : '' }`;
return (
<FormGroup>
<Select
{...this.props}
value={this.props.input.value}
onChange={(value) => this.props.input.onChange(value)}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
options={this.props.options}
placeholder={this.props.placeholder}
/>
<div className={className}>
<div className="text-help">
{touched ? error : ''}
</div>
</div>
</FormGroup>
);
Use the CustomSelect component in redux form field component as
<Field
name='country_name'
options={this.state.countries}
component={CustomSelect}
placeholder="Select your country"
/>

I had to call the onBlur without any argument. The issue with Hardik's answer was, it was not working in iPad (May be also in other iOS or touch devices. I was unable to check).
The onBlur event is automatically triggered along with the onChange event in iPad. It caused the select value to reset to its initial value. So I had to call onBlur method like this,
onBlur={(value) => input.onBlur()}
const RenderSelectInput = ({input, options, name, id}) => (
<Select
{...input}
id={id}
name={name}
options={options}
value={input.value}
onChange={(value) => input.onChange(value)}
onBlur={(value) => input.onBlur()}
/>
)
and used as,
<Field component={RenderSelectInput} />

Try setting onBlurResetInput property to false.
Something like.
const SelectInput = ({input: { onChange, value }, options, name, id}) => (
<Select
name={name}
value={value}
options={options}
onChange={onChange}
onBlurResetsInput={false}
/>
)
Hope this helps!

Related

What am I misunderstanding in my boolean radio group in Formik?

Following the Radio Group Example in the Formik docs and using Bootstrap 5 I've tried to create a boolean radio component that gets passed in a name and label. However, on render with the initialValues:
<Formik
initialValues={{
foo: false,
bar: false,
}}>
the no is selected because the initial value is set to false but whenever yes is chosen the radio will not fill in, component:
import React from 'react'
import PropTypes from 'prop-types'
import { Field } from 'formik'
const RadioBool = ({ name, label }) => {
const yesId = `${name}-yes`
const noId = `${name}-no`
return (
<>
<p id={`${name}-group-label`}>{label}:</p>
<div className="form-group mb-4" role="group" aria-labelledby={`${name}-group-label`}>
<div className="form-check">
<label htmlFor={yesId}>Yes</label>
<Field id={yesId} className="form-check-input" type="radio" name={name} value={true} />
</div>
<div className="form-check">
<label htmlFor={noId}>No</label>
<Field id={noId} className="form-check-input" type="radio" name={name} value={false} />
</div>
</div>
</>
)
}
RadioBool.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
}
export default RadioBool
but if checked is added to Yes, example:
<Field id={yesId} className="form-check-input" type="radio" name={name} value={true} checked />
the radio group works and I'm not sure why.
tests:
<RadioBool name="foo" label="Look at foo?" />
<RadioBool name="bar" label="Look at bar?" />
Research
How to add Radio Button in Formik Validations Reactjs?
How to create Radio buttons with Formik?
How to make use of Radio Group with useFormik Hook
how do you use onChange property on react formik radio field
formik radio button validation issues
Why does my boolean radio component not work in Formik unless checked is used on one <Field />?
The problem is described here Radio values must be strings, can't be numbers or booleans and as I see it's not solved 'from the box' yet.
In my TypeScript project I've created custom component. May it would be helpfull for you:
import React, { FC } from 'react';
type Props = {
name: string
value: boolean
checked: boolean
setValues: (values: React.SetStateAction<any>, shouldValidate?: boolean) => void;
}
const RadioButtonBooleanField: FC<Props> = ({name, value, checked, setValues}) => {
return (
<input type='radio' className="form-check-input" name={name} value={String(value)} checked={checked}
onChange={(e: any) => {
setValues((prevValues: any) => ({
...prevValues,
[e.target.name]: e.target.value === "true"
}))
}
}
/>
);
};
It can be used like this inside Formik component:
{({ errors, touched, values, setValues }) => (
<RadioButtonBooleanField name="IsExtendedView" value={false} checked={!values.IsExtendedView} setValues={setValues}/>
)}

How to use react-select with redux-form?

I am trying to integrate react-select using redux form...
Here is my code
import Select from 'react-select'
import StyledSelectField, { StyledMessages } from './style'
const SelectField = props => {
const { input, label, placeholder, options, meta, ...StyledProps } = props
const { onChange, onBlur, onFocus } = props.input
return (
<StyledSelectField {...StyledProps} meta={meta} hasValue={!!input.value}>
<label htmlFor={input.name}>{label}</label>
{placeholder && <div className="placeholder">{placeholder}</div>}
<Select
name={input.name}
value={input.value.value}
onChange={onChange}
onBlur={onBlur}
onFocus={onFocus}
options={options}
{...props}
/>
<StyledMessages>
{meta.touched &&
((meta.error && <span className="error">{meta.error}</span>) ||
(meta.warning && <span className="warning">{meta.warning}</span>))}
</StyledMessages>
</StyledSelectField>
)
}
class TestingCycleForm extends PureComponent {
render() {
const { preMonitoring, handleChange, handleSubmit } = this.props
return (<div>
<Field
label="18%"
name="patientPercentage"
className="form-control"
component={SelectField}
options={Config.get('/PATIENT_PERCENTAGE')}
/>
</div>)
}
}
All things are working but my input field gets cleared on focus out what I am doing wrong here?
Thanks in advance... Any help would be appreciated
You say “focus out” - does that mean it clears on blur? If so, does setting onBlurResetsInput and onCloseResetsInput to false help?
Update: here's the link to the props table from the github readme. You've got to set both onBlurResetsInput and onCloseResetsInput to false at the same time, onBlurResetsInput set to false, by itself, will do nothing.
And also you need to remove the onBlur prop from the select which causes field clear on Blur
<Select
name={input.name}
value={input.value.value}
onChange={onChange}
onBlurResetsInput={false}
onCloseResetsInput={false}
onFocus={onFocus}
options={options}
{...props}
/>

Set select default value doesn't work

Using Bulma CSS for a little help I made custom component to make me handle different kind of inputs with redux-form.
I would like to setup a default value for a select input.
import React from 'react';
import { Field } from 'redux-form';
const DropDownItem = ({ spec }) => {
const { name, defaultValue, items, iconLeft } = spec;
return (
<div className="field">
<div className="control has-icons-left">
<div className="select is-fullwidth">
<Field name={name} value={defaultValue} component="select">
{/* loop for countries */}
{items.map((country, i) => (
<option value={country} key={i}>
{country}
</option>
))}
</Field>
</div>
<div className="icon is-left">
<i className={iconLeft} />
</div>
</div>
</div>
);
};
export default DropDownItem;
I have the right value in defaultValue but the dropdown doesn't select this value by default.
The value of a <Field /> is controlled by the value in the redux-form store. You should set the initialValues for your redux-form form in the config when you initialize it:
import React from 'react'
import { Field, reduxForm } from 'redux-form'
let MyFormComponent = props => {
const { handleSubmit } = props;
return (
<form onSubmit={handleSubmit}>
<Field name="fieldName" component="input" /> // this field's default value will be 'defaultValue', as set in initialValues
...
</form>
)
}
MyFormComponent = reduxForm({
form: 'myForm',
initialValues: {
'fieldName': 'defaultValue',
...
}
})(MyFormComponent)
export default MyFormComponent;
You can also pass initialValues as a prop to your form component.
source
Seems like defaultValue has been disable in redux-form according to this thread on Github
Instead you can make use the initialValues API of redux-form
You can read more about initialValues on Redux Form Docs or initializefromstate

Unable to make the Checkbox work with redux-form and react-semantic-ui

I'm trying to use redux-form with react-semantic-ui and is having trouble with the Checkbox component. The Checkbox is not being checked. I've followed the example from the redux-form documentation, but no luck. Here's the Code snippet :
renderCheckBox = ({ input, label }) => {
console.log(input.value);
return (
<Form.Field>
<Checkbox
label={label}
checked={input.value ? true : false}
onChange={input.onChange}
/>
</Form.Field>
);
};
<Field
name="activated"
label="Activate?"
component={this.renderCheckBox}
/>
The output of console.log(input.value) is empty.
Reusable redux form checkbox with semantic ui
import React from 'react';
import { object } from 'prop-types';
import { Field } from 'redux-form/immutable';
import { Checkbox as CheckboxUI } from 'semantic-ui-react';
const Checkbox = ({
input: { value, onChange, ...input },
meta: { touched, error },
...rest
}) => (
<div>
<CheckboxUI
{...input}
{...rest}
defaultChecked={!!value}
onChange={(e, data) => onChange(data.checked)}
type="checkbox"
/>
{touched && error && <span>{error}</span>}
</div>
);
Checkbox.propTypes = {
input: object.isRequired,
meta: object.isRequired
};
Checkbox.defaultProps = {
input: null,
meta: null
};
export default props => <Field {...props} component={Checkbox} />;
How to use?
import Checkbox from './Checkbox';
<form>
...
<Checkbox name="example" />
...
</form>
If you want to know whether the checkbox is checked or not, you have to use
onChange={(e, { checked }) => input.onChange(checked)}
instead of
onChange={input.onChange}
Here's a working example

React + Bootstrap + Redux value not working in form

I'm defining a form in React with Bootstrap and Redux with the following code:
import React from 'react';
import { FormGroup, ControlLabel, FormControl, HelpBlock, Button } from 'react-bootstrap';
import { connect } from 'react-redux';
import './actions';
const _c = component => connect(s => s)(component);
const FieldGroup = ({ id, label, help, ...props }) => {
return (
<FormGroup controlId={id}>
<ControlLabel>{label}</ControlLabel>
<FormControl {...props} />
{help && <HelpBlock>{help}</HelpBlock>}
</FormGroup>
);
};
const LoginForm = _c(React.createClass({
render() {
return (
<form>
<FieldGroup
id="loginText"
type="text"
label="Text"
placeholder="Email"
value={this.props.user.email ? this.props.user.email[0] : ''}
/>
<FieldGroup
id="loginPassword"
label="Password"
type="password"
/>
<Button bsStyle="primary" bsSize="large">Login</Button>
</form>
);
}
}));
This works, and the value appears in the "Username" field, but it's not editable. I tried changing value={this.props.user.email ? this.props.user.email[0] : ''} to defaultValue={this.props.user.email ? this.props.user.email[0] : ''} and that makes it editable, but the default value never appears. What am I doing wrong?
(I would comment but I don't have 50 rep yet)
Sounds like your initial value may be undefined. Can you console.log(this.props.user.email[0]) and see that value?

Resources