Situation:
I have one normal select(categories), which determines what Options are loaded for the Select.Async from react-select.
Problem:
Lets say someone searches for an option in Select.Async, while category A
is selected. Then he realizes, that the option he is searching for is only available in category B
. So he switches category in the first select. But while he clicks out of the search box from Select.Async, the input he made vanishes and he has to type it again.
Is there something I can do to keep his input even if I update the set of options while the search input is not in focus?
<select id="categories">
<option value="1" selected>A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>
<Select.Async loadOptions={load} />
Complete code-sample
Situation:
I have one normal select(categories), which determines what Options are loaded for the Select.Async from react-select.
Problem:
Lets say someone searches for an option in Select.Async, while category A
is selected. Then he realizes, that the option he is searching for is only available in category B
. So he switches category in the first select. But while he clicks out of the search box from Select.Async, the input he made vanishes and he has to type it again.
Is there something I can do to keep his input even if I update the set of options while the search input is not in focus?
<select id="categories">
<option value="1" selected>A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>
<Select.Async loadOptions={load} />
Complete code-sample
Share Improve this question asked Aug 10, 2017 at 13:28 S.BabovicS.Babovic 3356 silver badges17 bronze badges3 Answers
Reset to default 6I found it out:
the property value
of Select.Async is not the actual value of the input field. If you want to set the value
of the input, there is a prop called inputRenderer. There you define an input within a div with all predefined inputProps
(simply write <input {...inputProps}
) and handle the value on your own.
render(){
var inputChange = (input) => this.setState({value: input});
var renderInput = (inputProps) => {
if(this.state.value == ''){
this.state.placeholder = 'Select ...';
} else {
this.state.placeholder = '';
}
var setCurserPosAtEnd = (event) => {
if(event.target)
event.target.setSelectionRange(event.target.value.length, event.target.value.length);
}
return (
<div className='Select-input'>
<input {...inputProps} value={this.state.value} onFocus={setCurserPosAtEnd} />
</div>
);
}
return(
...
<Select.Async
loadOptions={loadOptionHandler}
onBlurResetsInput={false}
onCloseResetsInput={false}
inputRenderer={renderInput}
placeholder={this.state.placeholder}
onInputChange={inputChange} />
...
);
}
I think this is the prop you are looking after:
<Select.Async loadOptions={load} onBlurResetsInput={false}/>
More options here
The full working example:
export default class Layout extends React.Component {
constructor()
{
super();
this.state = {value: ""};
}
render(){
var load = (input, callback) => this.load(input, callback);
return (
<div class="container">
<select id="select">
<option value="1" selected>A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>
<Select.Async
value={this.state.value}
onBlurResetsInput={false}
onChange={(newValue) => {
this.setState({value: newValue});
}}
loadOptions={load} />
</div>
);
}
load(input, callback){
var select = document.getElementById("select");
var selected = select.options[select.selectedIndex].value;
console.log(selected);
var options = [];
switch(selected){
case "1":
options = [{label: "A", value: 1}, {label: "B", value: 2}, {label: "C", value: 3}];
break;
case "2":
options = [{label: "D", value: 4}, {label: "E", value: 5}, {label: "F", value: 6}];
break;
case "3":
options = [{label: "G", value: 7}, {label: "H", value: 8}, {label: "I", value: 9}];
break;
}
callback(null, {
options: options
});
}
}
One way to do that is to use inputValue
prop.
Basically we modify the related state variable inside onInputChangeHandler and onMenuCloseHandler event handlers.
E.x.
const Bar = React.memo((props: PropsWithChildren<any>) => {
const searchRef = useRef<any>();
const [inputValue, setInputValue] = useState<any>('');
useEffect(() => {
setTimeout(() => {
searchRef.current.focus();
});
});
useEffect(() => {
if (props.lastSelectedOption)
setInputValue(props.lastSelectedOption.value);
}, [props.lastSelectedOption]);
const onSearchChangeHandler = async (event) => {
//...
});
const onInputChangeHandler = (inputValue, { action }) => {
setInputValue(inputValue);
if (action == 'input-change' && !inputValue) props.setLastSelectedOption(null);
}
const onKeyDownHandler = () => {
setTimeout(() => {
searchRef.current.focus();
});
};
const onMenuCloseHandler = () => setInputValue(inputValue);
return (
<div className="d-inline-flex w-100">
<AsyncSelect
className="rounded-pill flex-grow-1"
placeholder="Search.."
ref={searchRef}
inputValue={inputValue}
value={props.lastSelectedOption}
onChange={onChangeHandler}
onInputChange={onInputChangeHandler}
onKeyDown={onKeyDownHandler}
onMenuClose={onMenuCloseHandler}
/>
</div>
)
})
In the code above, prop lastSelectedOption is an object like this
{
value: event.value,
label: event.label
}