Skip to content

Commit

Permalink
Backport marmelab#9700
Browse files Browse the repository at this point in the history
  • Loading branch information
djhi authored and mjarosch committed Jul 1, 2024
1 parent 759d08a commit 703730c
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 77 deletions.
2 changes: 2 additions & 0 deletions docs/FieldsForRelationships.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ React-admin handles relationships *regardless of the capacity of the API to mana

React-admin provides helpers to fetch related records, depending on the type of relationship, and how the API implements it.

<iframe src="https://www.youtube-nocookie.com/embed/UeM31-65Wc4" 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>

## One-To-Many

When one record has many related records, this is called a one-to-many relationship. For instance, if an author has written several books, `authors` has a one-to-many relationship with `books`.
Expand Down
35 changes: 16 additions & 19 deletions docs/ReferenceArrayField.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ title: "The ReferenceArrayField Component"

Use `<ReferenceArrayField>` to display a list of related records, via a one-to-many relationship materialized by an array of foreign keys.

![ReferenceArrayField](./img/reference-array-field.png)
<iframe src="https://www.youtube-nocookie.com/embed/UeM31-65Wc4" 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>

`<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.

**Tip**: To edit the records of a one-to-many relationship, use [the `<ReferenceArrayInput>` component](./ReferenceArrayInput.md).

## Usage

For instance, let's consider a model where a `post` has many `tags`, materialized to a `tags_ids` field containing an array of ids:

Expand Down Expand Up @@ -35,41 +43,30 @@ A typical `post` record therefore looks like this:
}
```

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

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

`<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.

## Usage

`<ReferenceArrayField>` expects a `reference` attribute, which specifies the resource to fetch for the related records. It also expects a `source` attribute, which defines the field containing the list of ids to look for in the referenced resource.

For instance, if each post contains a list of tag ids (e.g. `{ id: 1234, title: 'Lorem Ipsum', tag_ids: [1, 23, 4] }`), here is how to fetch the list of tags for each post in a list, and display the `name` for each `tag` in a `<ChipField>`:

```jsx
import * as React from "react";
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" />
<ReferenceArrayField reference="tags" source="tag_ids" label="Tags" />
<EditButton />
</Datagrid>
</List>
);
```

![ReferenceArrayField](./img/reference-array-field.png)

`<ReferenceArrayField>` expects a `reference` attribute, which specifies the resource to fetch for the related records. It also expects a `source` attribute, which defines the field containing the list of ids to look for in the referenced resource.

`<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`:
Configure the `<Resource recordRepresentation>` to render related records in a meaningful 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" />
Expand Down
50 changes: 24 additions & 26 deletions docs/ReferenceField.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ title: "The ReferenceField Component"

`<ReferenceField>` is useful for displaying many-to-one and one-to-one relationships, e.g. the details of a user when rendering a post authored by that user.

![ReferenceField](./img/reference_field_show.png)
<iframe src="https://www.youtube-nocookie.com/embed/UeM31-65Wc4" 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>

## Usage

For instance, let's consider a model where a `post` has one author from the `users` resource, referenced by a `user_id` field.

Expand All @@ -22,18 +24,35 @@ For instance, let's consider a model where a `post` has one author from the `use
└──────────────┘
```

In that case, use `<ReferenceField>` to display the post author's id as follows:
In that case, use `<ReferenceField>` to display the post author's as follows:

```jsx
<ReferenceField source="user_id" reference="users" />
import { Show, SimpleShowLayout, ReferenceField, TextField, DateField } from 'react-admin';

export const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<DateField source="published_at" />
<ReferenceField source="user_id" reference="users" label="Author" />
</SimpleShowLayout>
</Show>
);
```

`<ReferenceField>` fetches the data, puts it in a [`RecordContext`](./useRecordContext.md), and renders the [`recordRepresentation`](./Resource.md#recordrepresentation) (the record `id` field by default).
`<ReferenceField>` fetches the data, puts it in a [`RecordContext`](./useRecordContext.md), and renders the [`recordRepresentation`](./Resource.md#recordrepresentation) (the record `id` field by default) wrapped in a link to the related user `<Edit>` page.

![ReferenceField](./img/reference_field_show.png)

So it's a good idea to configure the `<Resource recordRepresentation>` to render related records in a meaningul way. For instance, for the `users` resource, if you want the `<ReferenceField>` to display the full name of the author:

```jsx
<Resource name="users" list={UserList} recordRepresentation={(record) => `${record.first_name} ${record.last_name}`} />
<Resource
name="users"
list={UserList}
recordRepresentation={(record) => `${record.first_name} ${record.last_name}`}
/>
```

Alternately, if you pass a child component, `<ReferenceField>` will render it instead of the `recordRepresentation`. Usual child components for `<ReferenceField>` are other `<Field>` components (e.g. [`<TextField>`](./TextField.md)).
Expand All @@ -48,27 +67,6 @@ This component fetches a referenced record (`users` in this example) using the `

It uses `dataProvider.getMany()` instead of `dataProvider.getOne()` [for performance reasons](#performance). When using several `<ReferenceField>` in the same page (e.g. in a `<Datagrid>`), this allows to call the `dataProvider` once instead of once per row.

## Usage

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';

export const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<DateField source="published_at" />
<ReferenceField label="Author" source="user_id" reference="users" />
</SimpleShowLayout>
</Show>
);
```

With this configuration, `<ReferenceField>` wraps the user's name in a link to the related user `<Edit>` page.

## Props

| Prop | Required | Type | Default | Description |
Expand Down
45 changes: 13 additions & 32 deletions docs/ReferenceManyField.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ title: "The ReferenceManyField Component"

`<ReferenceManyField>` is useful for displaying a list of related records via a one-to-many relationship, when the foreign key is carried by the referenced resource.

![referenceManyField](./img/reference_many_field.png)
<iframe src="https://www.youtube-nocookie.com/embed/UeM31-65Wc4" 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>

This component fetches a list of referenced records by a reverse lookup of the current `record.id` in the `target` field of another resource (using the `dataProvider.getManyReference()` REST method), and puts them in a [`ListContext`](./useListContext.md). Its children can then use the data from this context. The most common case is to use [`<SingleFieldList>`](./SingleFieldList.md) or [`<Datagrid>`](./Datagrid.md) as child.

**Tip**: If the relationship is materialized by an array of ids in the initial record, use [the `<ReferenceArrayField>` component](./ReferenceArrayField.md) instead.

**Tip**: To edit the records of a one-to-many relationship, use [the `<ReferenceManyInput>` component](./ReferenceManyInput.md).

## Usage

For instance, if an `author` has many `books`, and each book resource exposes an `author_id` field:

Expand All @@ -25,12 +33,14 @@ For instance, if an `author` has many `books`, and each book resource exposes an
`<ReferenceManyField>` can render the titles of all the books by a given author.

```jsx
import { Show, SimpleShowLayout, ReferenceManyField, Datagrid, TextField, DateField } from 'react-admin';

const AuthorShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="first_name" />
<TextField source="last_name" />
<ReferenceManyField label="Books" reference="books" target="author_id">
<ReferenceManyField reference="books" target="author_id" label="Books">
<Datagrid>
<TextField source="title" />
<DateField source="published_at" />
Expand All @@ -41,42 +51,13 @@ const AuthorShow = () => (
);
```

This component fetches a list of referenced records by a reverse lookup of the current `record.id` in the `target` field of another resource (using the `dataProvider.getManyReference()` REST method), and puts them in a [`ListContext`](./useListContext.md). Its children can then use the data from this context. The most common case is to use [`<SingleFieldList>`](./SingleFieldList.md) or [`<Datagrid>`](./Datagrid.md) as child.

**Tip**: If the relationship is materialized by an array of ids in the initial record, use [the `<ReferenceArrayField>` component](./ReferenceArrayField.md) instead.

**Tip**: To edit the records of a one-to-many relationship, use [the `<ReferenceManyInput>` component](./ReferenceManyInput.md).

## Usage

For instance, here is how to show the title of the books written by a particular author in a show view.

```jsx
import { Show, SimpleShowLayout, TextField, ReferenceManyField, Datagrid, DateField } from 'react-admin';

export const AuthorShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="first_name" />
<TextField source="last_name" />
<DateField label="Born" source="dob" />
<ReferenceManyField label="Books" reference="books" target="author_id">
<Datagrid>
<TextField source="title" />
<DateField source="published_at" />
</Datagrid>
</ReferenceManyField>
</SimpleShowLayout>
</Show>
);
```
![referenceManyField](./img/reference_many_field.png)

`<ReferenceManyField>` accepts a `reference` attribute, which specifies the resource to fetch for the related record. It also accepts a `source` attribute which defines the field containing the value to look for in the `target` field of the referenced resource. By default, this is the `id` of the resource (`authors.id` in the previous example).

You can also use `<ReferenceManyField>` in a list, e.g. to display the authors of the comments related to each post in a list by matching `post.id` to `comment.post_id`:

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

export const PostList = () => (
Expand Down

0 comments on commit 703730c

Please sign in to comment.