Skip to content

Commit

Permalink
fix autocomplete sets previous value using onInputChange
Browse files Browse the repository at this point in the history
  • Loading branch information
tdnl committed Sep 5, 2023
1 parent 183dfa2 commit ee76753
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/AutocompleteInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ const CompanyInput = () => {
choices={choicesWithCurrentCompany}
optionText="name"
disabled={isLoading}
onInputChange={e => setFilter({ q: e.target.value })}
onInputChange={(_, newInputValue) => setFilter({ q: newInputValue })}
/>
);
}
Expand Down
24 changes: 24 additions & 0 deletions packages/ra-ui-materialui/src/input/AutocompleteInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1108,3 +1108,27 @@ export const TranslateChoice = () => {
</AdminContext>
);
};

export const WithInputOnChange = () => {
const [searchText, setSearchText] = React.useState('');

return (
<AdminContext dataProvider={dataProviderWithAuthors}>
<div>Search text: {searchText}</div>
<SimpleForm onSubmit={() => {}} defaultValues={{ role: 2 }}>
<AutocompleteInput
fullWidth
source="role"
resource="users"
choices={[
{ id: 1, name: 'bar' },
{ id: 2, name: 'foo' },
]}
onInputChange={(_, value: string) => {
setSearchText(value);
}}
/>
</SimpleForm>
</AdminContext>
);
};
71 changes: 44 additions & 27 deletions packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ const defaultFilterOptions = createFilterOptions();
*
* @example
* <AutocompleteInput source="author_id" options={{ color: 'secondary', InputLabelProps: { shrink: true } }} />
*
* Retrieve the value displayed in the textbox using the `onInputChange` prop:
*
* @example
* const [state, setState] = useState('')
*
* <AutocompleteInput source="gender" choices={choices} onInputChange={(_, newInputValue) => setState(newInputValue)} />
*/
export const AutocompleteInput = <
OptionType extends RaRecord = RaRecord,
Expand Down Expand Up @@ -440,33 +447,14 @@ If you provided a React element for the optionText prop, you must also provide t
useEffect(() => {
if (!multiple) {
const optionLabel = getOptionLabel(selectedChoice);
if (typeof optionLabel === 'string') {
setFilterValue(optionLabel);
} else {
if (typeof optionLabel !== 'string') {
throw new Error(
'When optionText returns a React element, you must also provide the inputText prop'
);
}
}
}, [getOptionLabel, multiple, selectedChoice]);

const handleInputChange: AutocompleteProps<
OptionType,
Multiple,
DisableClearable,
SupportCreate
>['onInputChange'] = (event, newInputValue, reason) => {
if (
event?.type === 'change' ||
!doesQueryMatchSelection(newInputValue)
) {
setFilterValue(newInputValue);
debouncedSetFilter(newInputValue);
}

onInputChange?.(event, newInputValue, reason);
};

const doesQueryMatchSelection = useCallback(
(filter: string) => {
let selectedItemTexts;
Expand Down Expand Up @@ -515,13 +503,42 @@ If you provided a React element for the optionText prop, you must also provide t
return filteredOptions;
};

const handleAutocompleteChange = (
event: any,
newValue: any,
_reason: string
) => {
handleChangeWithCreateSupport(newValue != null ? newValue : emptyValue);
};
const handleAutocompleteChange = useCallback<
AutocompleteProps<
OptionType,
Multiple,
DisableClearable,
SupportCreate
>['onChange']
>(
(_event, newValue, _reason) => {
handleChangeWithCreateSupport(
newValue != null ? newValue : emptyValue
);
},
[emptyValue, handleChangeWithCreateSupport]
);

const handleInputChange = useCallback<
AutocompleteProps<
OptionType,
Multiple,
DisableClearable,
SupportCreate
>['onInputChange']
>(
(event, newInputValue, reason) => {
if (
typeof event?.type === 'string' ||
!doesQueryMatchSelection(newInputValue)
) {
debouncedSetFilter(newInputValue);
}
setFilterValue(newInputValue);
onInputChange?.(event, newInputValue, reason);
},
[debouncedSetFilter, doesQueryMatchSelection, onInputChange]
);

const oneSecondHasPassed = useTimeout(1000, filterValue);

Expand Down

0 comments on commit ee76753

Please sign in to comment.