Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Improve doc for <Autocomplete onCreate> and similar props #9858

Merged
merged 2 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 67 additions & 16 deletions docs/AutocompleteInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,48 @@ const CreateCategory = () => {
```
{% endraw %}

If you want to customize the label of the "Create XXX" option, use [the `createItemLabel` prop](#createitemlabel).

If you just need to ask users for a single string to create the new option, you can use [the `onCreate` prop](#oncreate) instead.

## `createLabel`

When you set the `create` or `onCreate` prop, `<AutocompleteInput>` lets users create new options. By default, it renders a "Create" menu item at the bottom of the list. You can customize the label of that menu item by setting a custom translation for the `ra.action.create` key in the translation files.

![Create Label](./img/AutocompleteInput-createLabel.png)

Or, if you want to customize it just for this `<AutocompleteInput>`, use the `createLabel` prop:

You can customize the label of that menu item by setting a custom translation for the `ra.action.create` key in the translation files.

```jsx
<AutocompleteInput
source="author"
choices={authors}
onCreate={onCreate}
createLabel="Start typing to create a new item"
/>
```

## `createItemLabel`

If you set the `create` or `onCreate` prop, `<AutocompleteInput>` lets users create new options. When the text entered by the user doesn't match any option, the input renders a "Create XXX" menu item at the bottom of the list.

![Create Item Label](./img/AutocompleteInput-createItemLabel.png)

You can customize the label of that menu item by setting a custom translation for the `ra.action.create_item` key in the translation files.

Or, if you want to customize it just for this `<AutocompleteInput>`, use the `createItemLabel` prop:

```jsx
<AutocompleteInput
source="author"
choices={authors}
onCreate={onCreate}
createItemLabel="Add a new author: %{item}"
/>
```

## `debounce`

When used inside a [`<ReferenceInput>`](./ReferenceInput.md), `<AutocompleteInput>` will call `dataProvider.getList()` with the current input value as filter after a delay of 250ms. This is to avoid calling the API too often while users are typing their query.
Expand Down Expand Up @@ -369,39 +409,50 @@ const BookCreate = () => (

## `onCreate`

Use the `onCreate` prop to allow users to create new options on-the-fly. Its value must be a function. This lets you render a `prompt` to ask users about the new value. You can return either the new choice directly or a Promise resolving to the new choice.
Use the `onCreate` prop to allow users to create new options on the fly. This is equivalent to MUI's `<AutoComplete freeSolo>` prop.

<video controls playsinline muted>
<source src="./img/AutocompleteInput-onCreate.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>

`onCreate` must be a function that adds a new choice and returns it. This function can be async. The added choice must use the same format as the other choices (usually `{ id, name }`).

In the following example, users can create a new company by typing its name in the `<AutocompleteInput>`:

{% raw %}
```js
import { AutocompleteInput, Create, SimpleForm, TextInput } from 'react-admin';

const PostCreate = () => {
const categories = [
{ name: 'Tech', id: 'tech' },
{ name: 'Lifestyle', id: 'lifestyle' },
const ContactCreate = () => {
const companies = [
{ id: 1, name: 'Globex Corp.' },
{ id: 2, name: 'Soylent Inc.' },
];
return (
<Create>
<SimpleForm>
<TextInput source="title" />
<TextInput source="first_name" />
<TextInput source="last_name" />
<AutocompleteInput
onCreate={() => {
const newCategoryName = prompt('Enter a new category');
const newCategory = { id: newCategoryName.toLowerCase(), name: newCategoryName };
categories.push(newCategory);
return newCategory;
source="company"
choices={companies}
onCreate={companyName => {
const newCompany = { id: companies.length + 1, name: companyName };
companies.push(newCompany);
return newCompany;
}}
source="category"
choices={categories}
/>
</SimpleForm>
</Create>
);
}
```
{% endraw %}

If a prompt is not enough, you can use [the `create` prop](#create) to render a custom component instead.
If you want to customize the label of the "Create XXX" option, use [the `createItemLabel` prop](#createitemlabel).

When used inside a `<ReferenceInput>`, the `onCreate` prop should create a new record in the reference resource, and return it. See [Creating a New Reference](./ReferenceInput.md#creating-a-new-reference) for more details.

If a function is not enough, you can use [the `create` prop](#create) to render a custom component instead.

## `optionText`

Expand Down
110 changes: 84 additions & 26 deletions docs/ReferenceInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,32 +166,6 @@ You can filter the query used to populate the possible values. Use the `filter`

**Note**: When users type a search term in the `<AutocompleteInput>`, this doesn't affect the `filter` prop. Check the [Customizing the filter query](#customizing-the-filter-query) section below for details on how that filter works.

## `format`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved below as " Transforming The Input Value" because the format prop doesn't actually exist in this component.


By default, children of `<ReferenceInput>` transform `null` values from the `dataProvider` into empty strings.

If you want to change this behavior, you have to pass a custom `format` prop to the `<ReferenceInput>` *child component*, because **`<ReferenceInput>` doesn't have a `format` prop**. It is the responsibility of the child component to format the input value.

For instance, if you want to transform an option value before rendering, and the selection control is an `<AutocompleteInput>` (the default), set [the `<AutocompleteInput format>` prop](./Inputs.md#format) as follows:

```jsx
import { ReferenceInput, AutocompleteInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<AutocompleteInput format={value => value == null ? 'not defined' : value} />
</ReferenceInput>
```

The same goes if the child is a `<SelectInput>`:

```jsx
import { ReferenceInput, SelectInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<SelectInput format={value => value === undefined ? 'not defined' : null} />
</ReferenceInput>
```

## `label`

In an `<Edit>` or `<Create>` view, the `label` prop has no effect. `<ReferenceInput>` has no label, it simply renders its child (an `<AutocompleteInput>` by default). If you need to customize the label, set the `label` prop on the child element:
Expand Down Expand Up @@ -327,6 +301,32 @@ Then to display a selector for the contact company, you should call `<ReferenceI
<ReferenceInput source="company_id" reference="companies" />
```

## Transforming The Input Value

By default, children of `<ReferenceInput>` transform `null` values from the `dataProvider` into empty strings.

If you want to change this behavior, you have to pass a custom `format` prop to the `<ReferenceInput>` *child component*, because `<ReferenceInput>` doesn't have a `format` prop. It is the responsibility of the child component to format the input value.

For instance, if you want to transform an option value before rendering, and the selection control is an `<AutocompleteInput>` (the default), set [the `<AutocompleteInput format>` prop](./Inputs.md#format) as follows:

```jsx
import { ReferenceInput, AutocompleteInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<AutocompleteInput format={value => value == null ? 'not defined' : value} />
</ReferenceInput>
```

The same goes if the child is a `<SelectInput>`:

```jsx
import { ReferenceInput, SelectInput } from 'react-admin';

<ReferenceInput source="company_id" reference="companies">
<SelectInput format={value => value === undefined ? 'not defined' : null} />
</ReferenceInput>
```

## Customizing The Filter Query

By default, `<ReferenceInput>` renders an `<AutocompleteInput>`, which lets users type a search term to filter the possible values. `<ReferenceInput>` calls `dataProvider.getList()` using the search term as filter, using the format `filter: { q: [search term] }`.
Expand All @@ -341,6 +341,64 @@ const filterToQuery = searchText => ({ name_ilike: `%${searchText}%` });
</ReferenceInput>
```

## Creating a New Reference

When users don't find the reference they are looking for in the list of possible values, they need to create a new reference. If they have to quit the current form to create the reference, they may lose the data they have already entered. So a common feature for `<ReferenceInput>` is to let users create a new reference on the fly.

<iframe src="https://www.youtube-nocookie.com/embed/CIUp5MF6A1M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="aspect-ratio: 16 / 9;width:100%;margin-bottom:1em;"></iframe>

Children of `<ReferenceInput>` (`<AutocompleteInput>`, `<SelectInput>`, etc.) allow the creation of new choices via the `onCreate` prop. This displays a new "Create new" option in the list of choices. You can leverage this capability to create a new reference record.

The following example is a contact edition form using a `<ReferenceInput>` to select the contact company. Its child `<AutocompleteInput onCreate>` allows to create a new company on the fly if it doesn't exist yet.

```tsx
export const ContactEdit = () => {
const [create] = useCreate();
const notify = useNotify();
const handleCreateCompany = async (companyName?: string) => {
if (!companyName) return;
try {
const newCompany = await create(
'companies',
{ data: { name: companyName } },
{ returnPromise: true }
);
return newCompany;
} catch (error) {
notify('An error occurred while creating the company', {
type: 'error',
});
throw(error);
}
};
return (
<Edit>
<SimpleForm>
<TextInput source="first_name" />
<TextInput source="last_name" />
<ReferenceInput source="company_id" reference="companies">
<AutocompleteInput onCreate={handleCreateCompany} />
</ReferenceInput>
</SimpleForm>
</Edit>
);
};
```

In the example above, the `handleCreateCompany` function creates a new company with the name provided by the user, and returns it so that `<AutocompleteInput>` selects it.

You can learn more about the `onCreate` prop in the documentation of the selection input components:

- [`<AutocompleteInput onCreate>`](./AutocompleteInput.md#oncreate)
- [`<SelectInput onCreate>`](./SelectInput.md#oncreate)

If you need to ask the user for more details about the new reference, you display a custom element (e.g. a dialog) when the user selects the "Create" option. use the `create` prop for that instead of `onCreate`.

You can learn more about the `create` prop in the documentation of the selection input components:

- [`<AutocompleteInput create>`](./AutocompleteInput.md#create)
- [`<SelectInput create>`](./SelectInput.md#create)

## Tree Structure

If the reference resource is a tree, use [`<ReferenceNodeInput>`](./ReferenceNodeInput.md) instead of `<ReferenceInput>`.
Expand Down
38 changes: 34 additions & 4 deletions docs/SelectInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ const choices = possibleValues.map(value => ({ id: value, name: ucfirst(value) }

## `create`

To allow users to add new options, pass a React element as the `create` prop. `<SelectInput>` will then render a menu item at the bottom of the list, which will render the passed element when clicked.
To allow users to add new options, pass a React element as the `create` prop. `<SelectInput>` will then render a "Create" menu item at the bottom of the list, which will render the passed element when clicked.

{% raw %}
```jsx
Expand Down Expand Up @@ -222,8 +222,25 @@ const CreateCategory = () => {
```
{% endraw %}

If you want to customize the label of the "Create" option, use [the `createLabel` prop](#createlabel).

If you just need to ask users for a single string to create the new option, you can use [the `onCreate` prop](#oncreate) instead.

## `createLabel`

When you set the `create` or `onCreate` prop to let users create new options, `<SelectInput>` renders a "Create" menu item at the bottom of the list. You can customize the label of that menu item by setting a custom translation for the `ra.action.create` key in the translation files.

Or, if you want to customize it just for this `<SelectInput>`, use the `createLabel` prop:

```jsx
<SelectInput
source="category"
choices={categories}
onCreate={onCreate}
createLabel="Add a new category"
/>
```

## `disableValue`

By default, `<SelectInput>` renders the choices with the field `disabled: true` as disabled.
Expand Down Expand Up @@ -302,9 +319,16 @@ const UserCountry = () => {

## `onCreate`

Use the `onCreate` prop to allow users to create new options on-the-fly. Its value must be a function. This lets you render a `prompt` to ask users about the new value. You can return either the new choice directly or a Promise resolving to the new choice.
Use the `onCreate` prop to allow users to create new options on the fly. When enabled, `<SelectInput>` will render a "Create" menu item at the bottom of the list, which will call the `onCreate` function when selected.

<iframe src="https://www.youtube-nocookie.com/embed/CIUp5MF6A1M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="aspect-ratio: 16 / 9;width:100%;margin-bottom:1em;"></iframe>
<video controls autoplay playsinline muted loop>
<source src="./img/SelectInput-onCreate.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>

`onCreate` must be a function that adds a new choice and returns it to let `<SelectInput>` select it. The added choice must use the same format as the other choices (usually `{ id, name }`). `onCreate` can be an async function.

The following example shows how to trigger a prompt for the user to enter a new category:

{% raw %}
```js
Expand All @@ -318,7 +342,7 @@ const PostCreate = () => {
return (
<Create>
<SimpleForm>
<TextInput source="title" />
// ...
<SelectInput
onCreate={() => {
const newCategoryName = prompt('Enter a new category');
Expand All @@ -336,6 +360,12 @@ const PostCreate = () => {
```
{% endraw %}

If you want to customize the label of the "Create" option, use [the `createLabel` prop](#createlabel).

When used inside a `<ReferenceInput>`, the `onCreate` prop should create a new record in the reference resource, and return it. See [Creating a New Reference](./ReferenceInput.md#creating-a-new-reference) for more details.

<iframe src="https://www.youtube-nocookie.com/embed/CIUp5MF6A1M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="aspect-ratio: 16 / 9;width:100%;margin-bottom:1em;"></iframe>

If a prompt is not enough, you can use [the `create` prop](#create) to render a custom component instead.

## `optionText`
Expand Down
Binary file added docs/img/AutocompleteInput-createItemLabel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/AutocompleteInput-createLabel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/AutocompleteInput-onCreate.mp4
Binary file not shown.
Binary file added docs/img/SelectInput-onCreate.mp4
Binary file not shown.
Loading
Loading