Skip to content

Commit

Permalink
Merge pull request #4653 from marmelab/fix-autocomplete-array-input-d…
Browse files Browse the repository at this point in the history
…ependencies

Fix unnecessary AutocompleteArrayInput filter reset
  • Loading branch information
fzaninotto authored Apr 8, 2020
2 parents 1dc5ca6 + d493249 commit c10a5d5
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,43 @@ describe('<AutocompleteArrayInput />', () => {
formApi.change('tags', ['p']);
await waitForDomChange();
expect(setFilter).toHaveBeenCalledTimes(3);
expect(setFilter).toHaveBeenCalledWith('');
});

it('should reset filter only when needed, even if the value is an array of objects (fixes #4454)', async () => {
const setFilter = jest.fn();
let formApi;
const { getByLabelText } = render(
<Form
onSubmit={jest.fn()}
initialValues={{ tags: [{ id: 't' }] }}
render={({ form }) => {
formApi = form;
return (
<AutocompleteArrayInput
{...defaultProps}
choices={[
{ id: 't', name: 'Technical' },
{ id: 'p', name: 'Programming' },
]}
parse={value =>
value && value.map(v => ({ id: v }))
}
format={value => value && value.map(v => v.id)}
setFilter={setFilter}
/>
);
}}
/>
);
const input = getByLabelText('resources.posts.fields.tags');
fireEvent.change(input, { target: { value: 'p' } });
expect(setFilter).toHaveBeenCalledTimes(2);
expect(setFilter).toHaveBeenCalledWith('p');
formApi.change('tags', ['p']);
await waitForDomChange();
expect(setFilter).toHaveBeenCalledTimes(3);
expect(setFilter).toHaveBeenCalledWith('');
});

it('should allow customized rendering of suggesting item', () => {
Expand Down
12 changes: 7 additions & 5 deletions packages/ra-ui-materialui/src/input/AutocompleteArrayInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,19 @@ const AutocompleteArrayInput: FunctionComponent<
...rest,
});

const values = input.value || [];

const [filterValue, setFilterValue] = React.useState('');

const getSuggestionFromValue = useCallback(
value => choices.find(choice => get(choice, optionValue) === value),
[choices, optionValue]
);

const selectedItems = useMemo(
() => (input.value || []).map(getSuggestionFromValue),
[input.value, getSuggestionFromValue]
);
const selectedItems = useMemo(() => values.map(getSuggestionFromValue), [
...values,
getSuggestionFromValue,
]);

const { getChoiceText, getChoiceValue, getSuggestions } = useSuggestions({
allowDuplicates,
Expand Down Expand Up @@ -215,7 +217,7 @@ const AutocompleteArrayInput: FunctionComponent<
// would have to first clear the input before seeing any other choices
useEffect(() => {
handleFilterChange('');
}, [input.value, handleFilterChange]);
}, [...values, handleFilterChange]);

const handleKeyDown = useCallback(
(event: React.KeyboardEvent) => {
Expand Down

0 comments on commit c10a5d5

Please sign in to comment.