diff --git a/cypress/integration/create.js b/cypress/integration/create.js index 7b0521ae23d..679e86e2032 100644 --- a/cypress/integration/create.js +++ b/cypress/integration/create.js @@ -90,7 +90,7 @@ describe('Create Page', () => { value: 'Annamarie Mayer', }, ]); - cy.get('[role="option"]').trigger('click'); + cy.get('[role="option"]:first').trigger('click'); cy.get(CreatePage.elements.input('authors.0.role')).should( el => expect(el).to.exist ); diff --git a/docs/AutocompleteInput.md b/docs/AutocompleteInput.md index debc011c33c..7474af6042d 100644 --- a/docs/AutocompleteInput.md +++ b/docs/AutocompleteInput.md @@ -22,11 +22,23 @@ import { AutocompleteInput } from 'react-admin'; ]} /> ``` +**Tip**: If you want to populate the `choices` attribute with a list of related records, you should decorate `` with [``](./ReferenceInput.md), and leave the `choices` empty: + +```jsx +import { AutocompleteInput, ReferenceInput } from 'react-admin'; + + + + +``` + +**Tip**: `` is a stateless component, so it only allows to *filter* the list of choices, not to *extend* it. If you need to populate the list of choices based on the result from a `fetch` call (and if [``](./ReferenceInput.md) doesn't cover your need), you'll have to [write your own Input component](./Inputs.md#writing-your-own-input-component) based on MUI `` component. + ## Properties | Prop | Required | Type | Default | Description | |---------------------------|----------|-----------------------------------------------|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `choices` | Required | `Object[]` | `-` | List of items to autosuggest | +| `choices` | Optional | `Object[]` | `-` | List of items to autosuggest. Required if not inside a ReferenceInput. | | `create` | Optional | `Element` | `-` | A React Element to render when users want to create a new choice | | `createItemLabel` | Optional | `string` | `ra.action.create_item` | The label for the menu item allowing users to create a new choice. Used when the filter is not empty | | `emptyValue` | Optional | `any` | `''` | The value to use for the empty element | @@ -37,13 +49,13 @@ import { AutocompleteInput } from 'react-admin'; | `optionValue` | Optional | `string` | `id` | Field name of record containing the value to use as input value | | `inputText` | Optional | `Function` | `-` | Required if `optionText` is a custom Component, this function must return the text displayed for the current selection. | | `filterToQuery` | Optional | `string` => `Object` | `searchText => ({ q: [searchText] })` | How to transform the searchText into a parameter for the data provider | -| `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`. | +| `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 set up 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().length > 2` | | `suggestionLimit` | Optional | `number` | `null` | Limits the numbers of suggestions that are shown in the dropdown list | `` also accepts the [common input props](./Inputs.md#common-input-props). -## Usage +## `optionText` You can customize the properties to use for the option name and value, thanks to the `optionText` and `optionValue` attributes: @@ -66,7 +78,7 @@ 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: +`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 a text representation of the current selection: ```jsx const choices = [ @@ -96,6 +108,8 @@ const matchSuggestion = (filter, choice) => { /> ``` +## `translateChoice` + The choices are translated by default, so you can use translation identifiers as choices: ```jsx @@ -112,9 +126,17 @@ In that case, set the `translateChoice` prop to `false`. ``` -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). +## `shouldRenderSuggestions` + +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. ` { return val.trim().length > 2 }} />` would not render any suggestions until the 3rd character has been 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). +## `sx`: CSS API + +This component doesn't apply any custom styles on top of [MUI `` component](https://mui.com/components/autocomplete/). Refer to their documentation to know its CSS API. + +## Additional Props + `` renders a [MUI `` component](https://mui.com/components/autocomplete/) and it accepts the `` props: {% raw %} @@ -123,18 +145,6 @@ Ex. ` { return val.trim().le ``` {% endraw %} -**Tip**: If you want to populate the `choices` attribute with a list of related records, you should decorate `` with [``](./ReferenceInput.md), and leave the `choices` empty: - -```jsx -import { AutocompleteInput, ReferenceInput } from 'react-admin'; - - - - -``` - -**Tip**: `` is a stateless component, so it only allows to *filter* the list of choices, not to *extend* it. If you need to populate the list of choices based on the result from a `fetch` call (and if [``](./ReferenceInput.md) doesn't cover your need), you'll have to [write your own Input component](./Inputs.md#writing-your-own-input-component) based on MUI `` component. - ## Creating New Choices The `` can allow users to create a new choice if either the `create` or `onCreate` prop is provided. @@ -171,7 +181,7 @@ const PostCreate = () => { ``` {% endraw %} -Use the `create` prop when you want a more polished or complex UI. For example a MUI `` asking for multiple fields because the choices are from a referenced resource. +Use the `create` prop when you want a more polished or complex UI. For example an MUI `` asking for multiple fields because the choices are from a referenced resource. {% raw %} ```js @@ -253,9 +263,9 @@ const CreateCategory = () => { ``` {% endraw %} -**Tip:** As showcased in this example, react-admin provides a convenience hook for accessing the filter the user has already input in the ``: `useCreateSuggestionContext`. +**Tip:** As showcased in this example, react-admin provides a convenient hook for accessing the filter the user has already input in the ``: `useCreateSuggestionContext`. -The `Create %{item}` option will only be displayed once the user has already set a filter (by typing in some input). If you expect your users to create new items often, you can make this more user friendly by adding a placeholder text like this: +The `Create %{item}` option will only be displayed once the user has already set a filter (by typing in some input). If you expect your users to create new items often, you can make this more user-friendly by adding a placeholder text like this: {% raw %} ```diff @@ -287,7 +297,3 @@ const PostCreate = () => { } ``` {% endraw %} - -## `sx`: CSS API - -This component doesn't apply any custom styles on top of [MUI `` component](https://mui.com/components/autocomplete/). Refer to their documentation to know its CSS API. diff --git a/docs/ReferenceField.md b/docs/ReferenceField.md index 94001dc00e6..0c6af881955 100644 --- a/docs/ReferenceField.md +++ b/docs/ReferenceField.md @@ -22,7 +22,21 @@ For instance, let's consider a model where a `post` has one author from the `use └──────────────┘ ``` -In that case, use `` to display the post author's name as follows: +In that case, use `` to display the post author's id as follows: + +```jsx + +``` + +`` fetches the data, puts it in a [`RecordContext`](./useRecordContext.md), and renders the [`recordRepresentation`](./Resource.md#recordrepresentation) (the record `id` field by default). + +So it's a good idea to configure the `` to render related records in a meaningul way. For instance, for the `users` resource, if you want the `` to display the full name of the author: + +```jsx + `${record.first_name} ${record.last_name}`} /> +``` + +Alternately, if you pass a child component, `` will render it instead of the `recordRepresentation`. Usual child components for `` are other `` components (e.g. [``](./TextField.md)). ```jsx @@ -30,15 +44,13 @@ In that case, use `` to display the post author's name as follow ``` -A `` displays nothing on its own, it just fetches the data, puts it in a [`RecordContext`](./useRecordContext.md), and lets its children render it. Usual child components for `` are other `` components (e.g. [``](./TextField.md)). - This component fetches a referenced record (`users` in this example) using the `dataProvider.getMany()` method, and passes it to its child. -It uses `dataProvider.getMany()` instead of `dataProvider.getOne()` for performance reasons. When using several `` in the same page (e.g. in a ``), this allows to call the `dataProvider` once instead of once per row. +It uses `dataProvider.getMany()` instead of `dataProvider.getOne()` [for performance reasons](#performance). When using several `` in the same page (e.g. in a ``), this allows to call the `dataProvider` once instead of once per row. ## Usage -Here is how to render both a post and the `name` of its author in a show view: +Here is how to render both a post and the author name in a show view: ```jsx import { Show, SimpleShowLayout, ReferenceField, TextField, DateField } from 'react-admin'; @@ -49,9 +61,7 @@ export const PostShow = () => ( - - - + ); @@ -65,7 +75,7 @@ With this configuration, `` wraps the user's name in a link to t | ----------- | -------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------- | | `source` | Required | `string` | - | Name of the property to display | | `reference` | Required | `string` | - | The name of the resource for the referenced records, e.g. 'posts' | -| `children` | Required | `ReactNode` | - | One or more Field elements used to render the referenced record | +| `children` | Optional | `ReactNode` | - | One or more Field elements used to render the referenced record | | `emptyText` | Optional | `string` | '' | Defines a text to be shown when the field has no value or when the reference is missing | | `label` | Optional | `string | Function` | `resources.[resource].fields.[source]` | Label to use for the field when rendered in layout components | | `link` | Optional | `string | Function` | `edit` | Target of the link wrapping the rendered child. Set to `false` to disable the link. | @@ -78,9 +88,7 @@ With this configuration, `` wraps the user's name in a link to t `` can display a custom message when the referenced record is missing, thanks to the `emptyText` prop. ```jsx - - - + ``` `` renders the `emptyText`: @@ -94,25 +102,19 @@ By default, ``, `` and other layout components infer ```jsx {/* default label is 'User Id', or the translation of 'resources.posts.fields.user_id' if it exists */} - - - + ``` That's why you often need to set an explicit `label` on a ``: ```jsx - - - + ``` React-admin uses [the i18n system](./Translation.md) to translate the label, so you can use translation keys to have one label for each language supported by the interface: ```jsx - - - + ``` ## `link` @@ -120,27 +122,25 @@ React-admin uses [the i18n system](./Translation.md) to translate the label, so To change the link from the `` page to the `` page, set the `link` prop to "show". ```jsx - - - + ``` You can also prevent `` from adding a link to children by setting `link` to `false`. ```jsx // No link - - - + ``` You can also use a custom `link` function to get a custom path for the children. This function must accept `record` and `reference` as arguments. ```jsx // Custom path - `/my/path/to/${reference}/${record.id}`}> - - + `/my/path/to/${reference}/${record.id}`} +/> ``` ## `reference` @@ -150,9 +150,7 @@ The resource to fetch for the related record. For instance, if the `posts` resource has a `user_id` field, set the `reference` to `users` to fetch the user related to each post. ```jsx - - - + ``` ## `sortBy` @@ -160,9 +158,7 @@ For instance, if the `posts` resource has a `user_id` field, set the `reference` By default, when used in a ``, and when the user clicks on the column header of a ``, react-admin sorts the list by the field `source`. To specify another field name to sort by, set the `sortBy` prop. ```jsx - - - + ``` ## `sx`: CSS API @@ -255,9 +251,7 @@ export const PostList = () => ( - - - + diff --git a/docs/ReferenceInput.md b/docs/ReferenceInput.md index 74eb3972636..3916469d2c9 100644 --- a/docs/ReferenceInput.md +++ b/docs/ReferenceInput.md @@ -5,83 +5,148 @@ title: "The ReferenceInput Component" # `` -Use `` for foreign-key values, for instance, to edit the `post_id` of a `comment` resource. This component fetches the related record (using `dataProvider.getMany()`) as well as possible choices (using `dataProvider.getList()` in the reference resource). It delegates the rendering to its child component by providing the possible choices through the `ChoicesContext`. This context value can be accessed with the [`useChoicesContext`](./useChoicesContext.md) hook. +Use `` for foreign-key values, for instance, to edit the `post_id` of a `comment` resource. -This means you can use `` with any of [``](./SelectInput.md), [``](./AutocompleteInput.md), or [``](./RadioButtonGroupInput.md), or even with the component of your choice, provided they detect a `ChoicesContext` is available and get their choices from it. +![ReferenceInput](./img/reference-input.gif) + +## Usage The component expects a `source` and a `reference` attributes. For instance, to make the `post_id` for a `comment` editable: +```jsx +import { ReferenceInput } from 'react-admin'; + + +``` + +This component fetches the related record (using `dataProvider.getMany()`) as well as possible choices (using `dataProvider.getList()` in the reference resource). + +`` renders an [``](./AutocompleteInput.md) to let the user select the related record. + +You can tweak how this component fetches the possible values using the `page`, `perPage`, `sort`, and `filter` props. + +## Props + +| Prop | Required | Type | Default | Description | +|--------------------|----------|---------------------------------------------|----------------------------------|------------------------------------------------------------------------------------------| +| `source` | Required | `string` | - | Name of the entity property to use for the input value | +| `reference` | Required | `string` | '' | Name of the reference resource, e.g. 'posts'. | +| `children` | Optional | `ReactNode` | `` | The actual selection component | +| `filter` | Optional | `Object` | `{}` | Permanent filters to use for getting the suggestion list | +| `page` | Optional | `number` | 1 | The current page number | +| `perPage` | Optional | `number` | 25 | Number of suggestions to show | +| `sort` | Optional | `{ field: String, order: 'ASC' or 'DESC' }` | `{ field: 'id', order: 'DESC' }` | How to order the list of suggestions | +| `enableGetChoices` | Optional | `({q: string}) => boolean` | `() => true` | Function taking the `filterValues` and returning a boolean to enable the `getList` call. | + +**Note**: `` doesn't accept the [common input props](./Inputs.md#common-input-props) (like `label`) ; it is the responsibility of the child component to apply them. + +## `children` + +By default, `` renders an [``](./AutocompleteInput.md) to let end users select the reference record. + +You can pass a child component to customize the way the reference selector is displayed. + +For instance, to customize the input label, set the `label` prop on the child component: + +```jsx +import { ReferenceInput, AutocompleteInput } from 'react-admin'; + + + + +``` + +You can also use [``](./SelectInput.md) or [``](./RadioButtonGroupInput.md) instead of [``](./AutocompleteInput.md). + ```jsx import { ReferenceInput, SelectInput } from 'react-admin'; - + ``` -![ReferenceInput](./img/reference-input.gif) +You can even use a component of your own as child, provided it detects a `ChoicesContext` is available and gets their choices from it. -## Properties +The choices context value can be accessed with the [`useChoicesContext`](./useChoicesContext.md) hook. -| Prop | Required | Type | Default | Description | -|--------------------|----------|---------------------------------------------|----------------------------------|-------------------------------------------------------------------------------------------------------------------| -| `filter` | Optional | `Object` | `{}` | Permanent filters to use for getting the suggestion list | -| `page` | Optional | `number` | 1 | The current page number | -| `perPage` | Optional | `number` | 25 | Number of suggestions to show | -| `reference` | Required | `string` | '' | Name of the reference resource, e.g. 'posts'. | -| `sort` | Optional | `{ field: String, order: 'ASC' or 'DESC' }` | `{ field: 'id', order: 'DESC' }` | How to order the list of suggestions | -| `enableGetChoices` | Optional | `({q: string}) => boolean` | `() => true` | Function taking the `filterValues` and returning a boolean to enable the `getList` call. | +## `enableGetChoices` +You can make the `getList()` call lazy by using the `enableGetChoices` prop. This prop should be a function that receives the `filterValues` as parameter and return a boolean. This can be useful when using an `AutocompleteInput` on a resource with a lot of data. The following example only starts fetching the options when the query has at least 2 characters: -**Note**: `` doesn't accept the [common input props](./Inputs.md#common-input-props) ; it is the responsability of children to apply them. +```jsx + q.length >= 2} /> +``` -## Usage +## `filter` -You can tweak how this component fetches the possible values using the `page`, `perPage`, `sort`, and `filter` props. +You can filter the query used to populate the possible values. Use the `filter` prop for that. {% raw %} ```jsx -// by default, fetches only the first 25 values. You can extend this limit -// by setting the `perPage` prop. - - - + +``` +{% endraw %} -// by default, orders the possible values by id desc. You can change this order -// by setting the `sort` prop (an object with `field` and `order` properties). - - - +## `perPage` + +By default, `` fetches only the first 25 values. You can extend this limit by setting the `perPage` prop. + +```jsx + +``` + +## `reference` + +The name of the reference resource. For instance, in a Post form, if you want to edit the post author, the reference should be "authors". + +```jsx + +``` + +`` will use the reference resource `recordRepresentation` to display the selected record and the list of possible records. -// you can filter the query used to populate the possible values. Use the -// `filter` prop for that. +## `sort` + +By default, `` orders the possible values by `id` desc. You can change this order by setting the `sort` prop (an object with `field` and `order` properties). + +{% raw %} +```jsx - - + sort={{ field: 'title', order: 'ASC' }} +/> ``` {% endraw %} -**Tip** You can make the `getList()` call lazy by using the `enableGetChoices` prop. This prop should be a function that receives the `filterValues` as parameter and return a boolean. This can be useful when using an `AutocompleteInput` on a resource with a lot of data. The following example only starts fetching the options when the query has at least 2 characters: +## `source` + +The name of the property in the record that contains the identifier of the selected record. + +For instance, if a Post contains a reference to an author via an `author_id` property: + +```json +{ + "id": 456, + "title": "Hello world", + "author_id": 12 +} +``` + +Then to display a selector for the post author, you should call `` as follows: ```jsx - q.length >= 2}> - - + ``` -**Tip**: Why does `` use the `dataProvider.getMany()` method with a single value `[id]` instead of `dataProvider.getOne()` to fetch the record for the current value? Because when there are many `` for the same resource in a form (for instance when inside an ``), react-admin *aggregates* the calls to `dataProvider.getMany()` into a single one with `[id1, id2, ...]`. This speeds up the UI and avoids hitting the API too much. +## Performance + +Why does `` use the `dataProvider.getMany()` method with a single value `[id]` instead of `dataProvider.getOne()` to fetch the record for the current value? + +Because when there may be many `` for the same resource in a form (for instance when inside an ``), so react-admin *aggregates* the calls to `dataProvider.getMany()` into a single one with `[id1, id2, ...]`. + +This speeds up the UI and avoids hitting the API too much. diff --git a/docs/ReferenceOneField.md b/docs/ReferenceOneField.md index 354a0ba082d..acda54df06b 100644 --- a/docs/ReferenceOneField.md +++ b/docs/ReferenceOneField.md @@ -20,7 +20,7 @@ This field fetches a one-to-one relationship, e.g. the details of a book, when u `` behaves like ``: it uses the current `record` (a book in this example) to build a filter for the book details with the foreign key (`book_id`). Then, it uses `dataProvider.getManyReference('book_details', { target: 'book_id', id: book.id })` to fetch the related details, and takes the first one. -`` creates a `RecordContext` with the reference record, so you can use any component relying on this context (``, ``, etc.). +`` renders the [`recordRepresentation`](./Resource.md#recordrepresentation) of the related record. It also creates a `RecordContext` with the reference record, so you can use any component relying on this context (``, ``, etc.) as child. For the inverse relationships (the book linked to a book_detail), you can use a [``](./ReferenceField.md). @@ -51,7 +51,7 @@ const BookShow = () => ( | Prop | Required | Type | Default | Description | | ------------ | -------- | ------------------ | -------------------------------- | ----------------------------------------------------------------------------------- | -| `children` | Required | `Element` | - | The Field element used to render the referenced record | +| `children` | Optional | `Element` | - | The Field element used to render the referenced record | | `link` | Optional | `string | Function` | `edit` | Target of the link wrapping the rendered child. Set to `false` to disable the link. | | `reference` | Required | `string` | - | The name of the resource for the referenced records, e.g. 'book_details' | | `target` | Required | string | - | Target field carrying the relationship on the referenced resource, e.g. 'book_id' | diff --git a/docs/Resource.md b/docs/Resource.md index fa82f1aeb0e..a3ce7522ad1 100644 --- a/docs/Resource.md +++ b/docs/Resource.md @@ -84,6 +84,7 @@ The routing will map the component as follows: * [`name`](#name) * [`icon`](#icon) * [`options`](#icon) +* [`recordRepresentation`](#recordrepresentation) ## `icon` @@ -117,6 +118,26 @@ const App = () => ( ``` {% endraw %} +## `recordRepresentation` + +Whenever react-admin needs to render a record (e.g. in the title of an edition view, or in a ``), it uses the `recordRepresentation` to do it. By default, the representation of a record is its `id` field. But you can customize it by specifying the representation you want. + +For instance, to change the default representation of "users" records to render the full name instead of the id: + +```jsx + `${record.first_name} ${record.last_name}`} +/> +``` + +`recordRepresentation` can take 3 types of values: + +- a string (e.g. `'title'`) to specify the field to use as representation +- a function (e.g. `(record) => record.title`) to specify a custom string representation +- a React component (e.g. ``). In such components, use [`useRecordContext`](./useRecordContext.md) to access the record. + ## Resource Context `` also creates a `ResourceContext`, that gives access to the current resource name to all descendants of the main page components (`list`, `create`, `edit`, `show`). diff --git a/docs/SelectInput.md b/docs/SelectInput.md index 4bcb07bfcc7..e075058fe67 100644 --- a/docs/SelectInput.md +++ b/docs/SelectInput.md @@ -9,6 +9,8 @@ To let users choose a value in a list using a dropdown, use ``. It ![SelectInput](./img/select-input.gif) +## Usage + Set the `choices` attribute to determine the options (with `id`, `name` tuples): ```jsx @@ -21,11 +23,13 @@ import { SelectInput } from 'react-admin'; ]} /> ``` -## Properties +If, instead of showing choices as a dropdown list, you prefer to display them as a list of radio buttons, try the [``](./RadioButtonGroupInput.md). And if the list is too big, prefer the [``](./AutocompleteInput.md). + +## Props | Prop | Required | Type | Default | Description | |-------------------|----------|----------------------------|--------------------|----------------------------------------------------------------------------------------------------------------------------------------| -| `choices` | Required | `Object[]` | - | List of items to show as options | +| `choices` | Optional | `Object[]` | - | List of items to show as options. Required if not inside a ReferenceInput. | | `create` | Optional | `Element` | `-` | A React Element to render when users want to create a new choice | | `createLabel` | Optional | `string` | `ra.action.create` | The label for the menu item allowing users to create a new choice. Used when the filter is empty | | `disableValue` | Optional | `string` | 'disabled' | The custom field name used in `choices` to disable some choices | @@ -40,68 +44,75 @@ import { SelectInput } from 'react-admin'; `` also accepts the [common input props](./Inputs.md#common-input-props). -## Usage +## `choices` -You can customize the properties to use for the option name and value, thanks to the `optionText` and `optionValue` attributes: +An array of objects that represents the choices to show in the dropdown. The objects must have at least two fields: one to use for the option name, and the other to use for the option value. By default, `` will use the `id` and `name` fields. ```jsx const choices = [ - { _id: 123, full_name: 'Leo Tolstoi', sex: 'M' }, - { _id: 456, full_name: 'Jane Austen', sex: 'F' }, + { id: 'programming', name: 'Programming' }, + { id: 'lifestyle', name: 'Lifestyle' }, + { id: 'photography', name: 'Photography' }, ]; - + + ``` -`optionText` also accepts a function, so you can shape the option text at will: +If the choices have different keys, you can use [`optionText`](#optiontext) and [`optionValue`](#optionvalue) to specify which fields to use for the name and value. ```jsx const choices = [ - { id: 123, first_name: 'Leo', last_name: 'Tolstoi' }, - { id: 456, first_name: 'Jane', last_name: 'Austen' }, + { name: 'programming', label: 'Programming' }, + { name: 'lifestyle', label: 'Lifestyle' }, + { name: 'photography', label: 'Photography' }, ]; -const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`; - + + ``` -`optionText` also accepts a React Element, that will be cloned and receive the related choice as the `record` prop. You can use Field components there. +When used inside a ``, `` doesn't need a `choices` prop. Instead, it will use the records fetched by `` as choices, via the `ChoicesContext`. ```jsx -const choices = [ - { id: 123, first_name: 'Leo', last_name: 'Tolstoi' }, - { id: 456, first_name: 'Jane', last_name: 'Austen' }, -]; -const FullNameField = ({ record }) => {record.first_name} {record.last_name}; -}/> + + + ``` -An empty choice is always added (with a default `''` value, which you can overwrite with the `emptyValue` prop) on top of the options. You can furthermore customize the `MenuItem` for the empty choice by using the `emptyText` prop, which can receive either a string or a React Element, which doesn't receive any props. +See [Using in a `ReferenceInput>`](#using-in-a-referenceinput) below for more information. -```jsx - -``` +## `disableValue` -The choices are translated by default, so you can use translation identifiers as choices: +You can use a custom field name by setting `disableValue` prop: ```jsx const choices = [ - { id: 'M', name: 'myroot.gender.male' }, - { id: 'F', name: 'myroot.gender.female' }, + { _id: 123, full_name: 'Leo Tolstoi', sex: 'M' }, + { _id: 456, full_name: 'Jane Austen', sex: 'F' }, + { _id: 987, full_name: 'Jack Harden', sex: 'M', not_available: true }, ]; + ``` -However, in some cases, you may not want the choice to be translated. In that case, set the `translateChoice` prop to `false`. +## `emptyValue` + +An empty choice is always added (with a default `''` value, which you can overwrite with the `emptyValue` prop) on top of the options. You can furthermore customize the `MenuItem` for the empty choice by using the `emptyText` prop, which can receive either a string or a React Element, which doesn't receive any props. ```jsx - + ``` -Note that `translateChoice` is set to `false` when `` is a child of ``. +## `options` -Lastly, use the `options` attribute if you want to override any of MUI's `` attributes: +Use the `options` attribute if you want to override any of MUI's `` attributes: {% raw %} ```jsx @@ -113,17 +124,41 @@ Lastly, use the `options` attribute if you want to override any of MUI's `` with [``](./ReferenceInput.md), and leave the `choices` empty: +## `optionText` + +You can customize the properties to use for the option name and value, thanks to the `optionText` and `optionValue` attributes: ```jsx -import { SelectInput, ReferenceInput } from 'react-admin'; +const choices = [ + { _id: 123, full_name: 'Leo Tolstoi', sex: 'M' }, + { _id: 456, full_name: 'Jane Austen', sex: 'F' }, +]; + +``` - - - +`optionText` also accepts a function, so you can shape the option text at will: + +```jsx +const choices = [ + { id: 123, first_name: 'Leo', last_name: 'Tolstoi' }, + { id: 456, first_name: 'Jane', last_name: 'Austen' }, +]; +const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`; + ``` -If, instead of showing choices as a dropdown list, you prefer to display them as a list of radio buttons, try the [``](./RadioButtonGroupInput.md). And if the list is too big, prefer the [``](./AutocompleteInput.md). +`optionText` also accepts a React Element, that will be cloned and receive the related choice as the `record` prop. You can use Field components there. + +```jsx +const choices = [ + { id: 123, first_name: 'Leo', last_name: 'Tolstoi' }, + { id: 456, first_name: 'Jane', last_name: 'Austen' }, +]; +const FullNameField = ({ record }) => {record.first_name} {record.last_name}; +}/> +``` + +## `resettable` You can make the `SelectInput` component resettable using the `resettable` prop. This will add a reset button which will be displayed only when the field has a value. @@ -140,15 +175,55 @@ const choices = [ ``` -You can use a custom field name by setting `disableValue` prop: +## `sx`: CSS API + +The `` component accepts the usual `className` prop. You can also override many styles of the inner components thanks to the `sx` property (as most MUI components, see their [documentation about it](https://mui.com/customization/how-to-customize/#overriding-nested-component-styles)). This property accepts the following subclasses: + +| Rule name | Description | +|--------------------------|-----------------------------------------------------------| +| `& .RaSelectInput-input` | Applied to the underlying `ResettableTextField` component | + +To override the style of all instances of `` using the [MUI style overrides](https://mui.com/customization/globals/#css), use the `RaSelectInput` key. + +## `translateChoice` + +The choices are translated by default, so you can use translation identifiers as choices: ```jsx const choices = [ - { _id: 123, full_name: 'Leo Tolstoi', sex: 'M' }, - { _id: 456, full_name: 'Jane Austen', sex: 'F' }, - { _id: 987, full_name: 'Jack Harden', sex: 'M', not_available: true }, + { id: 'M', name: 'myroot.gender.male' }, + { id: 'F', name: 'myroot.gender.female' }, ]; - +``` + +However, in some cases, you may not want the choice to be translated. In that case, set the `translateChoice` prop to `false`. + +```jsx + +``` + +Note that `translateChoice` is set to `false` when `` is a child of ``. + +## Using In A ReferenceInput + +If you want to populate the `choices` attribute with a list of related records, you should decorate `` with [``](./ReferenceInput.md), and leave the `choices` empty: + +```jsx +import { SelectInput, ReferenceInput } from 'react-admin'; + + + + +``` + +In that case, `` uses the [`recordRepresentation`](./Resource.md#recordrepresentation) to render each choice from the list of possible records. You can override this behavior by setting the `optionText` prop: + +```jsx +import { SelectInput, ReferenceInput } from 'react-admin'; + + + + ``` ## Creating New Choices @@ -187,7 +262,7 @@ const PostCreate = () => { ``` {% endraw %} -Use the `create` prop when you want a more polished or complex UI. For example a MUI `` asking for multiple fields because the choices are from a referenced resource. +Use the `create` prop when you want a more polished or complex UI. For example an MUI `` asking for multiple fields because the choices are from a referenced resource. {% raw %} ```jsx @@ -267,14 +342,4 @@ const CreateCategory = () => { ); }; ``` -{% endraw %} - -## `sx`: CSS API - -The `` component accepts the usual `className` prop. You can also override many styles of the inner components thanks to the `sx` property (as most MUI components, see their [documentation about it](https://mui.com/customization/how-to-customize/#overriding-nested-component-styles)). This property accepts the following subclasses: - -| Rule name | Description | -|--------------------------|-----------------------------------------------------------| -| `& .RaSelectInput-input` | Applied to the underlying `ResettableTextField` component | - -To override the style of all instances of `` using the [MUI style overrides](https://mui.com/customization/globals/#css), use the `RaSelectInput` key. +{% endraw %} \ No newline at end of file diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 1725444ef83..fbf86b428e2 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -361,9 +361,7 @@ import { List, Datagrid, TextField, ReferenceField } from 'react-admin'; export const PostList = () => ( - - - + @@ -388,22 +386,16 @@ const App = () => ( ); ``` -When displaying the posts list, the app displays the `id` of the post author as a ``. This `id` field doesn't mean much, let's use the user `name` instead: +When displaying the posts list, the app displays the `id` of the post author. This doesn't mean much, let's use the user `name` instead. For that purpose, set the `recordRepresentation` prop of the "users" Resource: ```diff -// in src/posts.js -export const PostList = () => ( - - - -- -+ - - - - - - +// in src/App.js +const App = () => ( + + +- ++ + ); ``` @@ -411,7 +403,7 @@ The post list now displays the user names on each line. [![Post List With User Names](./img/tutorial_list_user_name.png)](./img/tutorial_list_user_name.png) -The `` component alone doesn't display anything. It just fetches the reference data, creates a `RecordContext` with the result, and renders its children (a `` in this case). +The `` component fetches the reference data, creates a `RecordContext` with the result, and renders the record representation (or its its children). **Tip**: Look at the network tab of your browser again: react-admin deduplicates requests for users, and aggregates them in order to make only *one* HTTP request to the `/users` endpoint for the whole Datagrid. That's one of many optimizations that keep the UI fast and responsive. @@ -428,9 +420,7 @@ export const PostList = () => ( - + + - - - + - - @@ -457,14 +447,14 @@ const App = () => ( - + - + ); ``` [![Post Edit Guesser](./img/tutorial_edit_guesser.gif)](./img/tutorial_edit_guesser.gif) -Users can display the edit page just by clicking on the Edit button. The form is already functional; it issues `PUT` requests to the REST API upon submission. +Users can display the edit page just by clicking on the Edit button. The form is already functional; it issues `PUT` requests to the REST API upon submission. And thanks to the `recordRepresentation` of the "users" Resource, the user name is displayed for the post author. Copy the `` code dumped by the guesser in the console to the `posts.js` file so that you can customize the view. Don't forget to `import` the new components from react-admin: @@ -480,7 +470,6 @@ import { Edit, SimpleForm, ReferenceInput, - SelectInput, TextInput, } from 'react-admin'; @@ -491,9 +480,7 @@ export const PostList = props => ( export const PostEdit = () => ( - - - + @@ -502,7 +489,7 @@ export const PostEdit = () => ( ); ``` -You can now adjust the `` component to disable the edition of the primary key (`id`), place it first, use the user `name` instead of the user `id` in the reference, and use a longer text input for the `body` field, as follows: +You can now adjust the `` component to disable the edition of the primary key (`id`), place it first, and use a longer text input for the `body` field, as follows: ```diff // in src/posts.js @@ -510,10 +497,7 @@ export const PostEdit = () => ( + - -- -+ - + - - @@ -523,9 +507,9 @@ export const PostEdit = () => ( ); ``` -If you've understood the `` component, the `` component will be no surprise. It's responsible for fetching the record, and displaying the page title. It passes the record down to the `` component, which is responsible for the form layout, default values, and validation. Just like ``, `` uses its children to determine the form inputs to display. It expects *input components* as children. ``, ``, and `` are such inputs. +If you've understood the `` component, the `` component will be no surprise. It's responsible for fetching the record, and displaying the page title. It passes the record down to the `` component, which is responsible for the form layout, default values, and validation. Just like ``, `` uses its children to determine the form inputs to display. It expects *input components* as children. `` and `` are such inputs. -The `` takes the same props as the `` (used earlier in the `` page). `` uses these props to fetch the API for possible references related to the current record (in this case, possible `users` for the current `post`). It then creates a context with the possible choices and renders its children (`` in this case), which are responsible for displaying the choices (via their `name` in that case), and letting the user select one. `` renders as a `