diff --git a/docs/Inputs.md b/docs/Inputs.md index 47a5c33ac6d..3c6e1faa655 100644 --- a/docs/Inputs.md +++ b/docs/Inputs.md @@ -162,6 +162,28 @@ const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`; ``` +`optionText` also accepts a custom Component. However, as the underlying Autocomplete component requires that the current selection is a string, if you opt for a Component, you must pass a function as the `inputText` prop. This function should return text representation of the current selection: + +```jsx +const choices = [ + { id: 123, first_name: 'Leo', last_name: 'Tolstoi' avatar='/pengouin' }, + { id: 456, first_name: 'Jane', last_name: 'Austen' avatar='/panda' }, +]; +const OptionRenderer = choice => ( + + + {choice.first_name} {choice.last_name} + +); +const inputText = choice => `${choice.first_name} ${choice.last_name}`; +} + inputText={inputText} +/> +``` + The choices are translated by default, so you can use translation identifiers as choices: ```jsx @@ -225,8 +247,9 @@ Lastly, would you need to override the props of the suggestions container (a `Po | `emptyValue` | Optional | anything | `''` | The value to use for the empty element | | `emptyText` | Optional | `string` | `''` | The text to use for the empty element | | `matchSuggestion` | Optional | `Function` | - | Required if `optionText` is a React element. Function returning a boolean indicating whether a choice matches the filter. `(filter, choice) => boolean` -| `optionText` | Optional | string | Function | `name` | Fieldname of record to display in the suggestion item or function which accepts the correct record as argument (`(record)=> {string}`) | +| `optionText` | Optional | string | Function | Component | `name` | Fieldname of record to display in the suggestion item or function which accepts the correct record as argument (`(record)=> {string}`) | | `optionValue` | Optional | `string` | `id` | Fieldname of record containing the value to use as input value | +| `inputText` | Optional | Function | `-` | If `optionText` is a custom Component, this function is needed to determine the text displayed for the current selection. | | `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`. | | `shouldRenderSuggestions` | Optional | Function | `() => true` | A function that returns a `boolean` to determine whether or not suggestions are rendered. Use this when working with large collections of data to improve performance and user experience. This function is passed into the underlying react-autosuggest component. Ex.`(value) => value.trim() > 2` | diff --git a/examples/simple/src/comments/CommentEdit.js b/examples/simple/src/comments/CommentEdit.js index ce31cdd9082..0ecba92dfd7 100644 --- a/examples/simple/src/comments/CommentEdit.js +++ b/examples/simple/src/comments/CommentEdit.js @@ -33,6 +33,14 @@ const useEditStyles = makeStyles({ }, }); +const OptionRenderer = ({ record }) => ( + + {record.title} - {record.id} + +); + +const inputText = record => `${record.title} - ${record.id}`; + const CommentEdit = props => { const classes = useEditStyles(); const { @@ -74,10 +82,15 @@ const CommentEdit = props => { fullWidth > + true + } + optionText={} + inputText={inputText} options={{ fullWidth: true }} /> + ', () => { } + inputText={record => record.name} matchSuggestion={(filter, choice) => true} choices={[ { id: 1, name: 'bar' }, diff --git a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx index 4e3aa86e085..84fb2aa934a 100644 --- a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx +++ b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx @@ -124,6 +124,7 @@ const AutocompleteInput: FunctionComponent< InputProps: undefined, }, optionText = 'name', + inputText, optionValue = 'id', parse, resource, @@ -136,6 +137,13 @@ const AutocompleteInput: FunctionComponent< variant = 'filled', ...rest }) => { + if (isValidElement(optionText) && !inputText) { + throw new Error(`If the optionText prop is a React element, you must also specify the inputText prop: + record.title} + />`); + } + warning( isValidElement(optionText) && !matchSuggestion, `If the optionText prop is a React element, you must also specify the matchSuggestion prop: @@ -219,8 +227,20 @@ const AutocompleteInput: FunctionComponent< // If we have a value, set the filter to its text so that // Downshift displays it correctly - setFilterValue(input.value ? getChoiceText(selectedItem) : ''); - }, [input.value, handleFilterChange, selectedItem, getChoiceText]); + setFilterValue( + input.value + ? inputText + ? inputText(getChoiceText(selectedItem).props.record) + : getChoiceText(selectedItem) + : '' + ); + }, [ + input.value, + handleFilterChange, + selectedItem, + getChoiceText, + inputText, + ]); const handleChange = useCallback( (item: any) => { @@ -267,10 +287,16 @@ const AutocompleteInput: FunctionComponent< handleFilterChange(''); // If we had a value before, set the filter back to its text so that // Downshift displays it correctly - setFilterValue(input.value ? getChoiceText(selectedItem) : ''); + setFilterValue( + input.value + ? inputText + ? inputText(getChoiceText(selectedItem).props.record) + : getChoiceText(selectedItem) + : '' + ); input.onBlur(event); }, - [getChoiceText, handleFilterChange, input, selectedItem] + [getChoiceText, handleFilterChange, input, inputText, selectedItem] ); const handleFocus = useCallback(