i'm using:
- react 15.6.2
- redux-form 7.2.0
- react-select 1.2.1
i don't have a codepen set up for this yet, it's complicated. hoping someone will see the problem from the source alone. i can dream, can't i?
i have a redux-form
displaying a invoice
object:
invoice = { client: { email: '[email protected]' } }
summary: i'm using react-select.creatable
as an autocomplete component for an email dropdown. selecting an email
sets the client
on the invoice
.
when i create a new email address and select it, then blur out of the input field, the input value gets cleared.
the new client
on the invoice
form still gets set correctly in the redux store, it just gets cleared from the Field's input value. why?
please note i am already manually calling input.onBlur() from the
Select
with the correct value, as per other answers. i think this has something to do with creating a new option.// redux-form field wrapping the custom autocomplete component
const clientOptions = clients.map(client => ({ label: client.email, value: client })) const isValidNewOption = ({ label }) => email.REG_EMAIL.test(label) const promptTextCreator = (label) => (
Send to ${label}
) const newOptionCreator = ({label, labelKey, valueKey}) => { return { label: label, value: { email: label } } }
// RFReactSelect, a react-select Creatable to act as an autocomplete with the ability to create a new option
import React, { PropTypes } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
RFReactSelect.defaultProps = {
multi: false,
className: ""
};
RFReactSelect.propTypes = {
input: PropTypes.shape({
name: PropTypes.string.isRequired,
onBlur: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func.isRequired,
}).isRequired,
options: PropTypes.array.isRequired,
multi: PropTypes.bool,
className: PropTypes.string,
onNewOptionClick: PropTypes.func,
};
export default function RFReactSelect(props) {
const { input , options, multi, className,
newOptionCreator, promptTextCreator, isValidNewOption } = props
const { name, value, onBlur, onChange, onFocus } = input;
const transformedValue = transformValue(value, options, multi);
return (
<Select.Creatable
className={className}
isValidNewOption={isValidNewOption}
name={name}
multi={multi}
newOptionCreator={newOptionCreator}
onSelectResetsInput={false}
onBlurResetsInput={false}
options={options}
onChange={multi
? multiChangeHandler(onChange)
: singleChangeHandler(onChange)
}
onBlur={() => onBlur(value)}
onFocus={onFocus}
promptTextCreator={promptTextCreator}
value={transformedValue}
valueKey='value'
/>
);
}
/**
* onChange from Redux Form Field has to be called explicity.
*/
function singleChangeHandler(func) {
return function handleSingleChange(value) {
func(value ? value.value : '');
};
}
/**
* onBlur from Redux Form Field has to be called explicity.
*/
function multiChangeHandler(func) {
return function handleMultiHandler(values) {
func(values.map(value => value.value));
};
}
/**
* For single select, Redux Form keeps the value as a string, while React Select
* wants the value in the form { value: "grape", label: "Grape" }
*
* * For multi select, Redux Form keeps the value as array of strings, while React Select
* wants the array of values in the form [{ value: "grape", label: "Grape" }]
*/
function transformValue(value, options, multi) {
if (multi && typeof value === 'string') return [];
const filteredOptions = options.filter(option => {
return multi
? value.indexOf(option.value) !== -1
: option.value === value;
});
return multi ? filteredOptions : filteredOptions[0];
}