Skip to content

Commit

Permalink
Merge pull request #8117 from marmelab/doc-referencearrayfield
Browse files Browse the repository at this point in the history
[doc] Fix ReferenceArrayField doc to use a child-less syntax first
  • Loading branch information
slax57 authored Aug 30, 2022
2 parents c2083e8 + 52efac8 commit 02ea7f1
Showing 1 changed file with 91 additions and 76 deletions.
167 changes: 91 additions & 76 deletions docs/ReferenceArrayField.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,25 @@ For instance, let's consider a model where a `post` has many `tags`, materialize
└──────────────┘
```

A typical `post` record therefore looks like this:

```json
{
"id": 1,
"title": "Hello world",
"body": "...",
"is_published": true,
"tags_ids": [1, 2, 3]
}
```

In that case, use `<ReferenceArrayField>` to display the post tags names as follows:

```jsx
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids" />
```

`<ReferenceArrayField>` fetches a list of referenced records (using the `dataProvider.getMany()` method), and and puts them in a [`ListContext`](./useListContext.md). A `<ReferenceArrayField>` displays nothing on its own, it just fetches the data and expects its children to render it. The most common case is to use [`<SingleFieldList>`](./SingleFieldList.md) or [`<Datagrid>`](./Datagrid.md) as child.
`<ReferenceArrayField>` fetches a list of referenced records (using the `dataProvider.getMany()` method), and puts them in a [`ListContext`](./useListContext.md). It then renders each related record, using its [`recordRepresentation`](./Resource.md#recordrepresentation), in a [`<ChipField>`](./ChipField.md).

**Tip**: If the relationship is materialized by a foreign key on the referenced resource, use [the `<ReferenceManyField>` component](./ReferenceManyField.md) instead.

Expand All @@ -45,33 +53,37 @@ For instance, if each post contains a list of tag ids (e.g. `{ id: 1234, title:

```jsx
import * as React from "react";
import { List, Datagrid, ChipField, ReferenceArrayField, SingleFieldList, TextField } from 'react-admin';
import { List, Datagrid, ReferenceArrayField, TextField } from 'react-admin';

export const PostList = () => (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids" />
<EditButton />
</Datagrid>
</List>
);
```

`<ReferenceArrayField>` fetches the `tag` resources related to each `post` resource by matching `post.tag_ids` to `tag.id`. Once it receives the related resources, `<ReferenceArrayField>` passes them to its child component using the `ids` and `data` props, so the child must be an iterator component (like `<SingleFieldList>` or `<Datagrid>`). The iterator component usually has one or more child `<Field>` components.
`<ReferenceArrayField>` fetches the `tag` resources related to each `post` resource by matching `post.tag_ids` to `tag.id`. By default, it renders one string by related record, via a [`<SingleFieldList>`](./SingleFieldList.md) with a [`<ChipField>`](./ChipField.md) child using the resource [`recordRepresentation`](./Resource.md#recordrepresentation) as source

Configure the `<Resource recordRepresentation>` to render related records in a meaningul way. For instance, for the `tags` resource, if you want the `<ReferenceArrayField>` to display the tag `name`:

```jsx
<Resource name="tags" list={TagList} recordRepresentation="name" />
```

You can change how the list of related records is rendered by passing a custom child reading the `ListContext` (e.g. a [`<Datagrid>`](./Datagrid.md)). See the [`children`](#children) section for details.

## Props

| Prop | Required | Type | Default | Description |
| ------------ | -------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| `source` | Required | `string` | - | Name of the property to display |
| `reference` | Required | `string` | - | The name of the resource for the referenced records, e.g. 'tags' |
| `children` | Required | `Element` | - | One or several elements that render a list of records based on a `ListContext` |
| `children` | Optional | `Element` | `<SingleFieldList>` | One or several elements that render a list of records based on a `ListContext` |
| `sortBy` | Optional | `string | Function` | `source` | When used in a `List`, name of the field to use for sorting when the user clicks on the column header. |
| `filter` | Optional | `Object` | - | Filters to use when fetching the related records (the filtering is done client-side) |
| `pagination` | Optional | `Element` | - | Pagination element to display pagination controls. empty by default (no pagination) |
Expand All @@ -80,6 +92,61 @@ export const PostList = () => (

`<ReferenceArrayField>` also accepts the [common field props](./Fields.md#common-field-props), except `emptyText` (use the child `empty` prop instead).

## `children`

By default, `<ReferenceArrayField>` renders one string by related record, via a [`<SingleFieldList>`](./SingleFieldList.md) with a [`<ChipField>`](./ChipField.md) using the resource [`recordRepresentation`](./Resource.md#recordrepresentation).

You can pass any component of your own as child, to render the list of related records in another way.

That means that using the field without child:

```jsx
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids" />
```

Is equivalent to:

```jsx
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
```

`<ReferenceArrayField>` creates a [`ListContext`](./useListContext.md), so you can use any child that uses a `ListContext`:

- [`<SingleFieldList>`](./SingleFieldList.md)
- [`<Datagrid>`](./Datagrid.md)
- [`<SimpleList>`](./SimpleList.md)
- [`<EditableDatagrid>`](./EditableDatagrid.md)
- [`<Calendar>`](./Calendar.md)
- Or a component of your own (check the [`usListContext`](./useListContext.md) chapter to learn how).

For instance, use a `<Datagrid>` to render the related records in a table:

```jsx
import * as React from "react";
import { Show, SimpleShowLayout, TextField, ReferenceArrayField, Datagrid, ShowButton } from 'react-admin';

export const PostShow = (props) => (
<Show {...props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<ShowButton />
</Datagrid>
</ReferenceArrayField>
<EditButton />
</SimpleShowLayout>
</Show>
);
```

## `filter`

`<ReferenceArrayField>` fetches all the related records, and displays them all, too. You can use the `filter` prop to filter the list of related records to display (this works by filtering the records client-side, after the fetch).
Expand All @@ -93,11 +160,7 @@ For instance, to render only tags that are 'published', you can use the followin
source="tag_ids"
reference="tags"
filter={{ is_published: true }}
>
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
/>
```
{% endraw %}

Expand All @@ -107,31 +170,19 @@ By default, `<SimpleShowLayout>`, `<Datagrid>` and other layout components infer

```jsx
{/* default label is 'Tag Ids', or the translation of 'resources.posts.fields.tag_ids' if it exists */}
<ReferenceArrayField source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
<ReferenceArrayField source="tag_ids" reference="tags" />
```

That's why you often need to set an explicit `label` on a `<ReferenceField>`:

```jsx
<ReferenceArrayField label="Tags" source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
<ReferenceArrayField label="Tags" source="tag_ids" reference="tags" />
```

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
<ReferenceArrayField label="resource.posts.fields.tags" source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
<ReferenceArrayField label="resource.posts.fields.tags" source="tag_ids" reference="tags" />
```

## `pagination`
Expand All @@ -148,21 +199,18 @@ import { Pagination, ReferenceArrayField } from 'react-admin';
source="tag_ids"
reference="tags"
perPage={10}
pagination={<Pagination />}>
...
</ReferenceArrayField>
pagination={<Pagination />}
/>
```

## `perPage`

`<ReferenceArrayField>` fetches *all* the related fields, and puts them all in a `ListContext`. If a record has a large number of related records, it my be a good idea to limit the number of displayed records. The `perPage` prop allows to create a client-side pagination for the related records.
`<ReferenceArrayField>` fetches *all* the related fields, and puts them all in a `ListContext`. If a record has a large number of related records, it may be a good idea to limit the number of displayed records. The `perPage` prop allows to create a client-side pagination for the related records.

For instance, to limit the display of related records to 10, you can use the following code:

```jsx
<ReferenceArrayField label="Tags" source="tag_ids" reference="tags" perPage={10}>
...
</ReferenceArrayField>
<ReferenceArrayField label="Tags" source="tag_ids" reference="tags" perPage={10} />
```

If you want to let the user display the remaining records, you have to pass a [`pagination`](#pagination) element.
Expand All @@ -174,11 +222,7 @@ The resource to fetch for the relateds record.
For instance, if the `posts` resource has a `tag_ids` field, set the `reference` to `tags` to fetch the tags related to each post.

```jsx
<ReferenceArrayField label="Tags" source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
<ReferenceArrayField label="Tags" source="tag_ids" reference="tags" />
```

## `sort`
Expand All @@ -196,11 +240,7 @@ For instance, to sort tags by title in ascending order, you can use the followin
source="tag_ids"
reference="tags"
sort={{ field: 'title', order: 'ASC' }}
>
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
/>
```
{% endraw %}

Expand All @@ -214,28 +254,3 @@ The `<ReferenceArrayField>` component accepts the usual `className` prop. You ca

To override the style of all instances of `<ReferenceArrayField>` using the [MUI style overrides](https://mui.com/customization/globals/#css), use the `RaReferenceArrayField` key.

## Example With A `<Datagrid>` Child

In an Edit of Show view, you can combine `<ReferenceArrayField>` with `<Datagrid>` to display related resources in a table. For instance, to display more details about the tags related to a post in the `PostShow` view:

```jsx
import * as React from "react";
import { Show, SimpleShowLayout, TextField, ReferenceArrayField, Datagrid, ShowButton } from 'react-admin';

export const PostShow = (props) => (
<Show {...props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<ReferenceArrayField label="Tags" reference="tags" source="tag_ids">
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<ShowButton />
</Datagrid>
</ReferenceArrayField>
<EditButton />
</SimpleShowLayout>
</Show>
);
```

0 comments on commit 02ea7f1

Please sign in to comment.