Skip to content

Commit

Permalink
Merge pull request #3667 from marmelab/autocomplete-array-input-2
Browse files Browse the repository at this point in the history
[RFR] New AutocompleteArrayInput
  • Loading branch information
fzaninotto authored Sep 12, 2019
2 parents 9b968bb + 539889c commit c082a6c
Show file tree
Hide file tree
Showing 18 changed files with 1,432 additions and 1,423 deletions.
27 changes: 24 additions & 3 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -891,11 +891,11 @@ const PostFilter = props =>
</Filter>;
```

## Complete rewrite of the AutocompleteInput component
## Complete rewrite of the AutocompleteInput and AutocompleteArrayInput components

We rewrote the `<AutocompleteInput>` component from scratch using [`downshift`](https://github.com/downshift-js/downshift), while the previous version was based on [react-autosuggest](http://react-autosuggest.js.org/). The new `<AutocompleteInput>` component is more robust and more future-proof, and its API didn't change.
We rewrote the `<AutocompleteInput>` and `<AutocompleteArrayInput>` components from scratch using [`downshift`](https://github.com/downshift-js/downshift), while the previous version was based on [react-autosuggest](http://react-autosuggest.js.org/). The new components are more robust and more future-proof, and their API didn't change.

There are two breaking changes in the new `<AutocompleteInput>`:
There are two breaking changes in the new `<AutocompleteInput>` and `<AutocompleteArrayInput>` components:

- The `inputValueMatcher` prop is gone. We removed a feature many found confusing: the auto-selection of an item when it was matched exactly. So react-admin no longer selects anything automatically, therefore the `inputValueMatcher` prop is obsolete

Expand All @@ -904,6 +904,10 @@ There are two breaking changes in the new `<AutocompleteInput>`:
source="role"
- inputValueMatcher={() => null}
/>
<AutocompleteArrayInput
source="role"
- inputValueMatcher={() => null}
/>
```

- Specific [`react-autosuggest` props](https://github.com/moroshko/react-autosuggest#props) (like `onSuggestionsFetchRequested`, `theme`, or `highlightFirstSuggestion`) are no longer supported, because the component now passes extra props to a `<Downshift>` component.
Expand All @@ -913,6 +917,23 @@ There are two breaking changes in the new `<AutocompleteInput>`:
source="role"
- highlightFirstSuggestion={true}
/>
<AutocompleteArrayInput
source="role"
- highlightFirstSuggestion={true}
/>
```

Besides, some props which were applicable to both components did not make sense for the `<AutocompleteArrayInput>` component:

- `allowEmpty`: As the `<AutocompleteArrayInput>` deals with arrays, it does not make sense to add an empty choice. This prop is no longer accepted and will be ignored.
- `limitChoicesToValue`: As the `<AutocompleteArrayInput>` deals with arrays and only accepts unique items, it does not make sense to show only the already selected items. This prop is no longer accepted and will be ignored.

```diff
<AutocompleteArrayInput
source="role"
- allowEmpty={true}
- limitChoicesToValue={true}
/>
```

## The `exporter` function has changed signature
Expand Down
31 changes: 3 additions & 28 deletions docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,6 @@ In that case, set the `translateChoice` prop to false.
<AutocompleteInput source="gender" choices={choices} translateChoice={false}/>
```

By default the component matches choices with the current input searchText: if it finds a match, this choice will be selected.
For example, given the choices `[{ id: 'M', name: 'Male', id: 'F', name: 'Female' }]`, when the user enters the text `male`, then the component will set the input value to `M`.
If you need to change how choices are matched, pass a custom function as `inputValueMatcher` prop.
For example, given the choices: `[{id:1,iso2:'NL',name:'Dutch'},{id:2,iso2:'EN',name:'English'},{id:3,iso2:'FR',name:'French'}]`, if you want to match choices on the iso2 code, you can create the following `inputValueMatcher` function:

```javascript
<AutocompleteInput inputValueMatcher={
(input, suggestion, getOptionText) =>
input.toUpperCase().trim() === suggestion.iso2 ||
input.toLowerCase().trim() === getOptionText(suggestion).toLowerCase().trim()
}/>
```

If you want to limit the initial choices shown to the current value only, you can set the `limitChoicesToValue` prop.

When dealing with a large amount of `choices` you may need to limit the number of suggestions that are rendered in order to maintain usable performance. The `shouldRenderSuggestions` is an optional prop that allows you to set conditions on when to render suggestions. An easy way to improve performance would be to skip rendering until the user has entered 2 or 3 characters in the search box. This lowers the result set significantly, and might be all you need (depending on your data set).
Expand Down Expand Up @@ -232,7 +219,9 @@ Lastly, would you need to override the props of the suggestions container (a `Po
## `<AutocompleteArrayInput>`
To let users choose multiple values in a list using a dropdown with autocompletion, use `<AutocompleteArrayInput>`. It renders using [material-ui-chip-input](https://github.com/TeamWertarbyte/material-ui-chip-input), [react-autosuggest](http://react-autosuggest.js.org/) and a `fuzzySearch` filter. Set the `choices` attribute to determine the options list (with `id`, `name` tuples).
To let users choose multiple values in a list using a dropdown with autocompletion, use `<AutocompleteArrayInput>`.
It renders using [downshift](https://github.com/downshift-js/downshift) and a `fuzzySearch` filter.
Set the `choices` attribute to determine the options list (with `id`, `name` tuples).
```jsx
import { AutocompleteArrayInput } from 'react-admin';
Expand Down Expand Up @@ -280,18 +269,6 @@ However, in some cases (e.g. inside a `<ReferenceInput>`), you may not want the
<AutocompleteArrayInput source="gender" choices={choices} translateChoice={false}/>
```
By default the component matches choices with the current input searchText. For example, given the choices `[{ id: 'M', name: 'Male', id: 'F', name: 'Female' }]`, when the user enters the text `male`, then the component will set the input value to `M`. If you need to change how choices are matched, pass a custom function as `inputValueMatcher` prop. For example, given the choices: `[{id:1,iso2:'NL',name:'Dutch'},{id:2,iso2:'EN',name:'English'},{id:3,iso2:'FR',name:'French'}]`, if you want to match choices on the iso2 code, you can create the following `inputValueMatcher` function:
```javascript
<AutocompleteArrayInput inputValueMatcher={
(input, suggestion, getOptionText) =>
input.toUpperCase().trim() === suggestion.iso2 ||
input.toLowerCase().trim() === getOptionText(suggestion).toLowerCase().trim()
}/>
```
If you want to limit the initial choices shown to the current value only, you can set the `limitChoicesToValue` prop.
When dealing with a large amount of `choices` you may need to limit the number of suggestions that are rendered in order to maintain usable performance. The `shouldRenderSuggestions` is an optional prop that allows you to set conditions on when to render suggestions. An easy way to improve performance would be to skip rendering until the user has entered 2 or 3 characters in the search box. This lowers the result set significantly, and might be all you need (depending on your data set).
Ex. `<AutocompleteArrayInput shouldRenderSuggestions={(val) => { return val.trim().length > 2 }} />` would not render any suggestions until the 3rd character was entered. This prop is passed to the underlying `react-autosuggest` component and is documented [here](https://github.com/moroshko/react-autosuggest#should-render-suggestions-prop).
Expand Down Expand Up @@ -338,8 +315,6 @@ If you need to override the props of the suggestions container (a `Popper` eleme
| `choices` | Required | `Object[]` | - | List of items to autosuggest |
| `resource` | Required | `string` | - | The resource working on. This field is passed down by wrapped components like `Create` and `Edit`. |
| `source` | Required | `string` | - | Name of field to edit, its type should match the type retrieved from `optionValue` |
| `allowEmpty` | Optional | `boolean` | `false` | If `false` and the searchText typed did not match any suggestion, the searchText will revert to the current value when the field is blurred. If `true` and the `searchText` is set to `''` then the field will set the input value to `null`. |
| `inputValueMatcher` | Optional | `Function` | `(input, suggestion, getOptionText) => input.toLowerCase().trim() === getOptionText(suggestion).toLowerCase().trim()` | Allows to define how choices are matched with the searchText while typing. |
| `optionValue` | Optional | `string` | `id` | Fieldname of record containing the value to use as input value |
| `optionText` | Optional | <code>string &#124; Function</code> | `name` | Fieldname of record to display in the suggestion item or function which accepts the current record as argument (`(record)=> {string}`) |
| `setFilter` | Optional | `Function` | null | A callback to inform the `searchText` has changed and new `choices` can be retrieved based on this `searchText`. Signature `searchText => void`. This function is automatically setup when using `ReferenceInput`. |
Expand Down
2 changes: 0 additions & 2 deletions packages/ra-ui-materialui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,8 @@
"inflection": "~1.12.0",
"jsonexport": "^2.4.1",
"lodash": "~4.17.5",
"material-ui-chip-input": "1.0.0",
"prop-types": "^15.6.1",
"ra-core": "^3.0.0-alpha.4",
"react-autosuggest": "^9.4.2",
"react-dropzone": "^10.1.7",
"react-final-form": "^6.3.0",
"react-final-form-arrays": "^3.1.1",
Expand Down
Loading

0 comments on commit c082a6c

Please sign in to comment.