I've been working on an extended version of Material UI's Autocomplete where I am implementing a feature that allows the user to move the option to the input via keyboard events (Arrow key up + down). The user should then be allowed to select one of the options via the ENTER key.
For some reason, the onChange event is not triggered and I am kind of puzzled to understand why this happens.
export default function Autocompleter() {
const [input, setInput] = React.useState(null);
const handleInputChange = (event, option, reason) => {
console.log('On input change triggered');
};
const handleOnChange = (event, value, reason) => {
console.log('On change triggered! ');
};
const handleHighlightChange = (event, option, reason) => {
if (option && reason === 'keyboard') {
setInput(option);
}
};
const handleFilterOptions = (currentOptions) => currentOptions;
const handleGetOptionsLabel = (option) => {
return option.label;
};
return (
<Autocomplete
id="combo-box-demo"
freeSolo={true}
value={input}
onChange={handleOnChange}
onInputChange={handleInputChange}
options={top100Films}
isOptionEqualToValue={(option, value) => option.label === value.label}
includeInputInList={true}
onHighlightChange={handleHighlightChange}
getOptionLabel={handleGetOptionsLabel}
filterOptions={handleFilterOptions}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
}
Here is also a working example:
https://stackblitz.com/edit/react-ts-rsodyc?file=index.tsx,App.tsx,Autocompleter.tsx
NOTE: This is a light example of my original code, but it should be enough to address the issue.
There are a few things I tried such as using inputValue in combination with the onHighlightChange but this does not seem to work either.
includeInputInList seemed to be the solution according to the doc, but it does nothing? Does anyone understand what it is supposed to do and is it helpful in my case?
UPDATE:
Updating the input state in onHighlightChange breaks the onChange. Unfortunately, I do want to update the input every time the user highlights an option via keyboard events.
Thank you for any kind of help and idea
Since I found that to my knowledge its not possible to check for a "Enter" key on the handleHighlightChange function I've come up with this.
highlightedInput is a seperate state for the highlighted value, this way you can keep track of the currently highlighted input. We set this in the handleHighlightChange after our checks.
We want to change our input state when we click Enter, normally when clicking the Enter key the dropdown closes. To handle this we can create a state for the open state of the dropdown. For this we need a handleOpen and a custom close handler handleOnclose here we can set the currently highlighted value (highlightedInput) to the actual input state.
const [input, setInput] = React.useState(null);
const [isOpen, setIsOpen] = React.useState(false);
const [highlightedInput, setHighlightedInput] = React.useState(null);
const handleOpen = () => {
setIsOpen(true);
};
const handleOnClose = (event, option, reason, details) => {
if (option && event.key === "Enter") {
setInput(highlightedInput);
}
setIsOpen(false);
};
const handleInputChange = (event, option, reason) => {
console.log("On input change triggered");
};
const handleOnChange = (event, value, reason) => {
console.log("On change triggered!");
};
const handleHighlightChange = (event, option, reason) => {
if (option && reason === "keyboard") {
setHighlightedInput(option);
}
};
const handleFilterOptions = (currentOptions) => currentOptions;
const handleGetOptionsLabel = (option) => {
return option.label;
};
Note that we changed the value from the AutoComplete to the highlightedInput instead of input.
return (
<React.Fragment>
<Autocomplete
id="combo-box-demo"
freeSolo={true}
open={isOpen}
onOpen={handleOpen}
onClose={handleOnClose}
value={highlightedInput}
onChange={handleOnChange}
onInputChange={handleInputChange}
options={top100Films}
isOptionEqualToValue={(option, value) => option.label === value.label}
includeInputInList={true}
onHighlightChange={handleHighlightChange}
getOptionLabel={handleGetOptionsLabel}
filterOptions={handleFilterOptions}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
<div style={{ height: "200px" }}></div>
{input?.label}
</React.Fragment>
);
Live version
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