Reputation: 193
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
Upvotes: 3
Views: 8682
Reputation: 4642
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>
);
Upvotes: 3
Reputation: 1085
The onChange
handler runs when the user selects an option from the drop down. Seams that you want the onInputChange
event. That one fires when you type in the input field.
Upvotes: 1