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] Fix section title level in List and Create/Edit chapters #6010

Merged
merged 1 commit into from
Mar 8, 2021
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
26 changes: 15 additions & 11 deletions docs/CreateEdit.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ That's enough to display the post edit form:

![post edition form](./img/post-edition.png)

**Tip**: You might find it cumbersome to repeat the same input components for both the `<Create>` and the `<Edit>` view. In practice, these two views almost never have exactly the same form inputs. For instance, in the previous snippet, the `<Edit>` views show related comments to the current post, which makes no sense for a new post. Having two separate sets of input components for the two views is, therefore, a deliberate choice. However, if you have the same set of input components, export them as a custom Form component to avoid repetition.
**Tip**: You might find it cumbersome to repeat the same input components for both the `<Create>` and the `<Edit>` view. In practice, these two views almost never have exactly the same form inputs. For instance, in the previous snippet, the `<Edit>` view shows related comments to the current post, which makes no sense for a new post. Having two separate sets of input components for the two views is, therefore, a deliberate choice. However, if you have the same set of input components, export them as a custom Form component to avoid repetition.

React-admin injects a few props to the `create` and `edit` views: the `resource` name, the `basePath` (the root URL), the `permissions`, and, in the case of the `edit` view, the record `id`. That's why you need to pass the `props` to the `<Create>` and `<Edit>` components.

Expand Down Expand Up @@ -245,7 +245,7 @@ const Aside = ({ record }) => (

By default, the `Create` and `Edit` views render the main form inside a material-ui `<Card>` element. The actual layout of the form depends on the `Form` component you're using (`<SimpleForm>`, `<TabbedForm>`, or a custom form component).

Some form layouts also use `Card`, in which case the user ends up seeing a card inside a card, which is bad UI. To avoid that, you can override the main form container by passing a `component` prop :
Some form layouts also use `Card`, in which case the user ends up seeing a card inside a card, which is bad UI. To avoid that, you can override the main page container by passing a `component` prop :

```jsx
// use a div as root component
Expand Down Expand Up @@ -325,7 +325,7 @@ The `<Edit>` view exposes two buttons, Save and Delete, which perform "mutations
- `optimistic`: The mutation is applied locally and the side effects are executed immediately. Then the mutation is passed to the dataProvider. If the dataProvider returns successfully, nothing happens (as the mutation was already applied locally). If the dataProvider returns in error, the page is refreshed and an error notification is shown.
- `undoable` (default): The mutation is applied locally and the side effects are executed immediately. Then a notification is shown with an undo button. If the user clicks on undo, the mutation is never sent to the dataProvider, and the page is refreshed. Otherwise, after a 5 seconds delay, the mutation is passed to the dataProvider. If the dataProvider returns successfully, nothing happens (as the mutation was already applied locally). If the dataProvider returns in error, the page is refreshed and an error notification is shown.

By default, pages using `<Edit>` use the `undoable` mutation mode. This is part of the "optimistic rendering" strategy of react-admin ; it makes the user interactions more reactive.
By default, pages using `<Edit>` use the `undoable` mutation mode. This is part of the "optimistic rendering" strategy of react-admin ; it makes user interactions more reactive.

You can change this default by setting the `mutationMode` prop - and this affects both the Save and Delete buttons. For instance, to remove the ability to undo the changes, use the `optimistic` mode:

Expand Down Expand Up @@ -557,7 +557,7 @@ const PostEdit = props => (

## Prefilling a `<Create>` Record

You may need to prepopulate a record based on another one. For that use case, use the `<CloneButton>` component. It expects a `record` and a `basePath` (usually injected to children of `<Datagrid>`, `<SimpleForm>`, `<SimpleShowLayout>`, etc.), so it's as simple to use as a regular field or input.
Users may need to create a copy of an existing record. For that use case, use the `<CloneButton>` component. It expects a `record` and a `basePath` (usually injected to children of `<Datagrid>`, `<SimpleForm>`, `<SimpleShowLayout>`, etc.), so it's as simple to use as a regular field or input.

For instance, to allow cloning all the posts from the list:

Expand All @@ -575,9 +575,9 @@ const PostList = props => (
);
```

Alternately, you may need to prepopulate a record based on a *related* record. For instance, in a `PostList` component, you may want to display a button to create a comment related to the current post. Clicking on that button would lead to a `CommentCreate` page where the `post_id` is preset to the id of the Post.
**Note**: `<CloneButton>` is designed to be used in a `<Datagrid>` and in an edit view `<Actions>` component, not inside the form `<Toolbar>`. The `Toolbar` is basically for submitting the form, not for going to another resource.

**Note** `<CloneButton>` is designed to be used in an edit view `<Actions>` component, not inside a `<Toolbar>`. The `Toolbar` is basically for submitting the form, not for going to another resource.
Alternately, users need to prepopulate a record based on a *related* record. For instance, to create a comment related to an exising post.

By default, the `<Create>` view starts with an empty `record`. However, if the `location` object (injected by [react-router-dom](https://reacttraining.com/react-router/web/api/location)) contains a `record` in its `state`, the `<Create>` view uses that `record` instead of the empty object. That's how the `<CloneButton>` works under the hood.

Expand Down Expand Up @@ -637,6 +637,8 @@ const CreateRelatedCommentButton = ({ record }) => (
```
{% endraw %}

Should you use the location `state` or the location `search`? The latter modifies the URL, so it's only necessary if you want to build cross-application links (e.g. from one admin to the other). In general, using the location `state` is a safe bet.

## The `<EditGuesser>` component

Instead of a custom `Edit`, you can use the `EditGuesser` to determine which inputs to use based on the data returned by the API.
Expand Down Expand Up @@ -2078,7 +2080,9 @@ export const PostEdit = (props) => (
);
```

## Displaying Fields or Inputs Depending on the User Permissions
## Recipes

### Displaying Fields or Inputs Depending on the User Permissions

You might want to display some fields, inputs or filters only to users with specific permissions.

Expand Down Expand Up @@ -2140,7 +2144,7 @@ export const UserEdit = ({ permissions, ...props }) =>
```
{% endraw %}

## Changing The Success or Failure Notification Message
### Changing The Success or Failure Notification Message

Once the `dataProvider` returns successfully after save, users see a generic notification ("Element created" / "Element updated"). You can customize this message by passing a custom success side effect function as [the `<Edit onSuccess>` prop](#onsuccess):

Expand Down Expand Up @@ -2193,7 +2197,7 @@ If the form has several save buttons, you can also pass a custom `onSuccess` or

**Tip**: The notify message will be translated.

## Altering the Form Values Before Submitting
### Altering the Form Values Before Submitting

Sometimes, you may want to alter the form values before sending them to the `dataProvider`. For those cases, use [the `transform` prop](#transform) either on the view component (`<Create>` or `<Edit>`) or on the `<SaveButton>` component.

Expand Down Expand Up @@ -2246,7 +2250,7 @@ const dataProvider = {
}
```

## Using `onSave` To Alter the Form Submission Behavior
### Using `onSave` To Alter the Form Submission Behavior

**Deprecated**: use the `<SaveButton onSuccess>` prop instead.

Expand Down Expand Up @@ -2293,7 +2297,7 @@ const SaveWithNoteButton = props => {

The `onSave` value should be a function expecting 2 arguments: the form values to save, and the redirection to perform.

## Grouping Inputs
### Grouping Inputs

Sometimes, you may want to group inputs in order to make a form more approachable. You may use a [`<TabbedForm>`](#the-tabbedform-component), an [`<AccordionForm>`](#the-accordionform-component) or you may want to roll your own layout. In this case, you might need to know the state of a group of inputs: whether it's valid or if the user has changed them (dirty/pristine state).

Expand Down
194 changes: 98 additions & 96 deletions docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ const PostList = props => (

The default value for the `component` prop is `Card`.

## Synchronize With URL
### Synchronize With URL

When a List based component (eg: `PostList`) is passed to the `list` prop of a `<Resource>`, it will automatically synchronize its parameters with the browser URL (using react-router location). However, when used anywhere outside of a `<Resource>`, it won't synchronize, which can be useful when you have multiple lists on a single page for example.

Expand Down Expand Up @@ -2004,7 +2004,7 @@ export const PostList = (props) => (

**Tip**: To let users hide or show columns at will, check the [`<SelectColumnsButton>`](https://marmelab.com/ra-enterprise/modules/ra-preferences#selectcolumnsbutton-store-datagrid-columns-in-preferences)<img class="icon" src="./img/premium.svg" />, an [Enterprise Edition](https://marmelab.com/ra-enterprise) component.

The `<Datagrid>` is an **iterator** component: it gets an array of ids and a data store from the `ListContext`, and iterates over the ids to display each record. Another example of iterator component is [`<SingleFieldList>`](#the-singlefieldlist-component).
The `<Datagrid>` is an **iterator** component: it gets an array of ids and a data store from the `ListContext`, and iterates over the ids to display each record. Other examples of iterator component are [`<SimpleList>`](#the-simplelist-component) and [`<SingleFieldList>`](#the-singlefieldlist-component).

### Body element

Expand Down Expand Up @@ -2213,6 +2213,28 @@ export const PostList = props => (
```
{% endraw %}

### Performance

When displaying large pages of data, you might experience some performance issues.
This is mostly due to the fact that we iterate over the `<Datagrid>` children and clone them.

In such cases, you can opt-in for an optimized version of the `<Datagrid>` by setting its `optimized` prop to `true`.
Be aware that you can't have dynamic children, such as those displayed or hidden by checking permissions, when using this mode.

```jsx
const PostList = props => (
<List {...props}>
<Datagrid optimized>
<TextField source="id" />
<TextField source="title" />
<TextField source="views" />
</Datagrid>
</List>
);

export default withStyles(styles)(PostList);
```

### CSS API

The `Datagrid` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys:
Expand Down Expand Up @@ -2323,92 +2345,6 @@ export const ProductList = (props) => (

For this kind of use case, you need to use a [custom datagrid body component](#body-element).

### Performance

When displaying large pages of data, you might experience some performance issues.
This is mostly due to the fact that we iterate over the `<Datagrid>` children and clone them.

In such cases, you can opt-in for an optimized version of the `<Datagrid>` by setting its `optimized` prop to `true`.
Be aware that you can't have dynamic children, such as those displayed or hidden by checking permissions, when using this mode.

```jsx
const PostList = props => (
<List {...props}>
<Datagrid optimized>
<TextField source="id" />
<TextField source="title" />
<TextField source="views" />
</Datagrid>
</List>
);

export default withStyles(styles)(PostList);
```

### With Custom Query

You can use the `<Datagrid>` component with [custom queries](./Actions.md#usequery-hook), provided you pass the result to a `<ListContextProvider>`:

{% raw %}
```jsx
import keyBy from 'lodash/keyBy'
import {
useQuery,
ResourceContextProvider,
ListContextProvider,
Datagrid,
TextField,
Pagination,
Loading,
} from 'react-admin'

const CustomList = () => {
const [page, setPage] = useState(1);
const perPage = 50;
const { data, total, loading, error } = useQuery({
type: 'getList',
resource: 'posts',
payload: {
pagination: { page, perPage },
sort: { field: 'id', order: 'ASC' },
filter: {},
}
});

if (loading) {
return <Loading />
}
if (error) {
return <p>ERROR: {error}</p>
}
return (
<ResourceContextProvider value="posts">
<ListContextProvider
value={{
basePath: '/posts',
data: keyBy(data, 'id'),
ids: data.map(({ id }) => id),
currentSort: { field: 'id', order: 'ASC' },
selectedIds: [],
}}
>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="title" />
</Datagrid>
<Pagination
page={page}
perPage={perPage}
setPage={setPage}
total={total}
/>
</ListContextProvider>
</ResourceContextProvider>
);
}
```
{% endraw %}

## The `<SimpleList>` component

<a href="./img/simple-list.gif"><img src="./img/simple-list.gif" style="height:300px" alt="The `<SimpleList>` component"></a>
Expand Down Expand Up @@ -2736,7 +2672,9 @@ export const Basic = () => (

Check [the `ra-calendar` documentation](https://marmelab.com/ra-enterprise/modules/ra-calendar) for more details.

## Using a Custom Iterator
## Recipes

### Using a Custom Iterator

A `<List>` can delegate to any iterator component - `<Datagrid>` is just one example. An iterator component can get the data to display from [the `useListContext` hook](#uselistcontext). The data comes in two constants:

Expand Down Expand Up @@ -2803,13 +2741,7 @@ export const CommentList = (props) => (

As you can see, nothing prevents you from using `<Field>` components inside your own components... provided you inject the current `record`. Also, notice that components building links require the `basePath` component, which is also available from `useListContext`.

## Third-Party Components

You can find components for react-admin in third-party repositories.

- [ra-customizable-datagrid](https://github.com/fizix-io/ra-customizable-datagrid): plugin that allows to hide / show columns dynamically.

## Displaying Fields Depending On The User Permissions
### Displaying Fields Depending On The User Permissions

You might want to display some fields or filters only to users with specific permissions.

Expand Down Expand Up @@ -2858,3 +2790,73 @@ export const UserList = ({ permissions, ...props }) => {
{% endraw %}

**Tip**: Note how the `permissions` prop is passed down to the custom `filters` component.

### Rendering `<Datagrid>` With A Custom Query

You can use the `<Datagrid>` component with [custom queries](./Actions.md#usequery-hook), provided you pass the result to a `<ListContextProvider>`:

{% raw %}
```jsx
import keyBy from 'lodash/keyBy'
import {
useQuery,
ResourceContextProvider,
ListContextProvider,
Datagrid,
TextField,
Pagination,
Loading,
} from 'react-admin'

const CustomList = () => {
const [page, setPage] = useState(1);
const perPage = 50;
const { data, total, loading, error } = useQuery({
type: 'getList',
resource: 'posts',
payload: {
pagination: { page, perPage },
sort: { field: 'id', order: 'ASC' },
filter: {},
}
});

if (loading) {
return <Loading />
}
if (error) {
return <p>ERROR: {error}</p>
}
return (
<ResourceContextProvider value="posts">
<ListContextProvider
value={{
basePath: '/posts',
data: keyBy(data, 'id'),
ids: data.map(({ id }) => id),
currentSort: { field: 'id', order: 'ASC' },
selectedIds: [],
}}
>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="title" />
</Datagrid>
<Pagination
page={page}
perPage={perPage}
setPage={setPage}
total={total}
/>
</ListContextProvider>
</ResourceContextProvider>
);
}
```
{% endraw %}

## Third-Party Components

You can find components for react-admin in third-party repositories.

- [ra-customizable-datagrid](https://github.com/fizix-io/ra-customizable-datagrid): plugin that allows to hide / show columns dynamically.