Skip to content

Commit

Permalink
Merge pull request #9614 from marmelab/doc-function-field
Browse files Browse the repository at this point in the history
[Doc] Improve FunctionField documentation
  • Loading branch information
slax57 committed Jan 26, 2024
2 parents b9b6e8b + c548d7f commit 2c6d52f
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 7 deletions.
112 changes: 106 additions & 6 deletions docs/FunctionField.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,122 @@ title: "The FunctionField Component"

# `<FunctionField>`

If you need a special function to render a field, `<FunctionField>` is the perfect match. It passes the `record` to a `render` function supplied by the developer. For instance, to display the full name of a `user` record based on `first_name` and `last_name` properties:
If you need a special function to render a field, `<FunctionField>` is the perfect match. It executes a `render` function using the current record as parameter.

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

`<FunctionField>` requires a `render` prop, which is a function that takes the current record as argument and returns a string or an element.

For instance, to display the full name of a `user` record based on `first_name` and `last_name` properties:

```jsx
import { FunctionField } from 'react-admin';
import { List, Datagrid, FunctionField } from 'react-admin';

<FunctionField label="Name" render={record => `${record.first_name} ${record.last_name}`} />
const UserList = () => (
<List>
<Datagrid>
<FunctionField
source="last_name"
render={record => `${record.first_name} ${record.last_name}`}
/>
...
</Datagrid>
</List>
);
```

## Properties
Theoretically, you can omit the `source` for the `<FunctionField>` since you provide the render function. However, when used inside a `<Datagrid>`, providing the `source` prop (or the `sortBy` prop) is required to make the column sortable. When a user clicks on a column, `<Datagrid>` uses these properties to sort the data.

`<FunctionField>` is based on [the `useRecordContext` hook](./useRecordContext.md).

## Props

| Prop | Required | Type | Default | Description |
| -------- | -------- | -------- | ------- | -------------------------------------------------------------------------- |
| `render` | Required | function | - | A function returning a string (or an element) to display based on a record |

`<FunctionField>` also accepts the [common field props](./Fields.md#common-field-props).

**Tip**: Technically, you can omit the `source` and `sortBy` properties for the `<FunctionField>` since you provide the render function. However, providing a `source` or a `sortBy` will allow the `Datagrid` to make the column sortable, since when a user clicks on a column, the `Datagrid` uses these properties to sort. Should you provide both, `sortBy` will override `source` for sorting the column.
## `render`

The `render` prop accepts a function that takes the current record as argument and returns a string or an element.

```tsx
// return a string
const render = (record: any) => `${record.first_name} ${record.last_name}`;

// return an element
const render = (record: any) => (
<>{record.first_name} <strong>{record.last_name}</strong></>
);
```

React-admin wraps the result of the `render` function in a `<Typography>` component.

Since this function executes in a [RecordContext](./useRecordContext.md), you can even use other Field components to compute the value:

```tsx
import { List, Datagrid, FunctionField, TextField } from 'react-admin';

const render = () => (
<span>
<TextField source="first_name" />{' '}
<TextField source="last_name" />
</span>
);
const UserList = () => (
<List>
<Datagrid>
<FunctionField source="last_name" label="Name" render={render} />
...
</Datagrid>
</List>
);
```

However, if you only need to combine Field components, prefer [the `<WrapperField>` component](./WrapperField.md) for a simpler syntax:

```tsx
import { List, Datagrid, WrapperField, TextField } from 'react-admin';

const UserList = () => (
<List>
<Datagrid>
<WrapperField label="Name" source="last_name">
<TextField source="first_name" />
<TextField source="last_name" />
</WrapperField>
...
</Datagrid>
</List>
);
```

## TypeScript

To type the `record` argument of the `render` function, provide the record's type as a generic parameter to the component:

```tsx
import { List, Datagrid, FunctionField } from 'react-admin';

interface User {
id: number;
first_name: string;
last_name: string;
}

**Tip**: If you want to combine two existing Field components, check [the `<WrapperField>` component](./WrapperField.md) instead.
const UserList = () => (
<List>
<Datagrid>
<FunctionField<User>
source="last_name"
label="Name"
render={record => `${record.first_name} ${record.last_name}`}
/>
...
</Datagrid>
</List>
);
```
7 changes: 6 additions & 1 deletion docs/WrapperField.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ title: "The WrapperField Component"

This component simply renders its children. Why would you want to use such a dumb component? To combine several fields in a single cell (in a `<Datagrid>`), in a single row (in a `<SimpleShowLayout>`) or in a group of inputs (in a `<SimpleFormConfigurable>`) .

## Usage

`<WrapperField>` allows to define the `label` and sort field for a combination of fields:

```jsx
Expand Down Expand Up @@ -44,5 +46,8 @@ const PostEdit = () => (
);
```

**Tip**: If you just want to combine two fields in a string, check [the `<FunctionField>` component](./FunctionField.md) instead.

## Props

**Tip**: If you just want to combine two fields in a string, check [the `<FunctionField>` component](./FunctionField.md) instead.
`<WrapperField>` accepts the [common field props](./Fields.md#common-field-props).

0 comments on commit 2c6d52f

Please sign in to comment.