| layout | default |
|---|---|
| title | The ArrayField Component |
<ArrayField> renders an embedded array of objects.
<ArrayField> creates a ListContext with the field value, and renders its children components - usually iterator components like <Datagrid> or <SingleFieldList>.
<ArrayField> is ideal for collections of objects, e.g. tags and backlinks in the following post object:
{
id: 123,
title: 'Lorem Ipsum Sit Amet',
tags: [{ name: 'dolor' }, { name: 'sit' }, { name: 'amet' }],
backlinks: [
{
uuid: '34fdf393-f449-4b04-a423-38ad02ae159e',
date: '2012-08-10T00:00:00.000Z',
url: 'https://example.com/foo/bar.html',
},
{
uuid: 'd907743a-253d-4ec1-8329-404d4c5e6cf1',
date: '2012-08-14T00:00:00.000Z',
url: 'https://blog.johndoe.com/2012/08/12/foobar.html',
}
]
}Leverage <ArrayField> e.g. in a Show view, to display the tags as a <SingleFieldList> and the backlinks as a <Datagrid>:
import {
ArrayField,
ChipField,
Datagrid,
Show,
SimpleShowLayout,
SingleFieldList,
TextField
} from 'react-admin';
const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="title" />
<ArrayField source="tags">
<SingleFieldList linkType={false}>
<ChipField source="name" size="small" />
</SingleFieldList>
</ArrayField>
<ArrayField source="backlinks">
<Datagrid bulkActionButtons={false}>
<TextField source="uuid" />
<TextField source="date" />
<TextField source="url" />
</Datagrid>
</ArrayField>
</SimpleShowLayout>
</Show>
)| Prop | Required | Type | Default | Description |
|---|---|---|---|---|
children |
Required | ReactNode |
The component to render the list. | |
filter |
Optional | object |
The filter to apply to the list. | |
perPage |
Optional | number |
1000 | The number of items to display per page. |
sort |
Optional | { field, order} |
The sort to apply to the list. | |
storeKey |
Optional | string |
The key to use to store the records selection state |
<ArrayField> accepts the common field props, except emptyText (use the child empty prop instead).
<ArrayField> relies on useList to filter, paginate, and sort the data, so it accepts the same props.
<ArrayField> renders its children component wrapped in a <ListContextProvider>. Commonly used child components are <Datagrid>, <SingleFieldList>, and <SimpleList>.
{/* using SingleFieldList as child */}
<ArrayField source="tags">
<SingleFieldList linkType={false}>
<ChipField source="name" />
</SingleFieldList>
</ArrayField>
{/* using Datagrid as child */}
<ArrayField source="backlinks">
<Datagrid>
<TextField source="uuid" />
<TextField source="date" />
<TextField source="url" />
</Datagrid>
</ArrayField>
{/* using SimpleList as child */}
<ArrayField source="backlinks">
<SimpleList
primaryText={record => record.url}
secondaryText={record => record.date}
/>
</ArrayField>You can also render custom JSX, leveraging the <WithListContext> component:
<ArrayField source="backlinks">
<WithListContext render={({ data }) => (
<ul>
{data.map(backlink => (
<li key={backlink.id}>{backlink.url}</li>
))}
</ul>
)} />
</ArrayField>Or a custom component, leveraging the useListContext hook:
const Backlinks = () => {
const { data } = useListContext();
return (
<ul>
{data.map(backlink => (
<li key={backlink.id}>{backlink.url}</li>
))}
</ul>
);
};
const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="title" />
<ArrayField source="backlinks">
<Backlinks />
</ArrayField>
</SimpleShowLayout>
</Show>
)You can use the filter prop to display only a subset of the items in the array. For instance, to display only the backlinks for a particular day:
{% raw %}
<ArrayField source="backlinks" filter={{ date: '2012-08-10T00:00:00.000Z' }}>
<Datagrid>
<TextField source="uuid" />
<TextField source="date" />
<TextField source="url" />
</Datagrid>
</ArrayField>{% endraw %}
The filtering capabilities are very limited. For instance, there is no "greater than" or "less than" operator. You can only filter on the equality of a field.
If the value is a large array, and you don't need to display all the items, you can use the perPage prop to limit the number of items displayed.
As <ArrayField> creates a ListContext, you can use the <Pagination> component to navigate through the items.
import {
ArrayField,
Datagrid,
Pagination,
Show,
SimpleShowLayout,
TextField
} from 'react-admin';
const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="title" />
<ArrayField source="backlinks" perPage={5}>
<Datagrid>
<TextField source="uuid" />
<TextField source="date" />
<TextField source="url" />
</Datagrid>
<Pagination />
</ArrayField>
</SimpleShowLayout>
</Show>
);By default, <ArrayField> displays the items in the order they are stored in the field. You can use the sort prop to change the sort order.
{% raw %}
<ArrayField source="tags" sort={{ field: 'name', order: 'ASC' }}>
<SingleFieldList linkType={false}>
<ChipField source="name" />
</SingleFieldList>
</ArrayField>{% endraw %}
By default, ArrayField stores the selection state in localStorage so users can revisit the page and find the selection preserved. The key for storing this state is based on the resource name, formatted as ${resource}.selectedIds.
When displaying multiple lists with the same data source, you may need to distinguish their selection states. To achieve this, assign a unique storeKey to each ArrayField. This allows each list to maintain its own selection state independently.
In the example below, two ArrayField components display the same data source (books), but each stores its selection state under a different key (customOne.selectedIds and customTwo.selectedIds). This ensures that both components can coexist on the same page without interfering with each other's state.
<Stack direction="row" spacing={2}>
<ArrayField
source="books"
storeKey="customOne"
>
<Datagrid>
<TextField source="title" />
</Datagrid>
</ArrayField>
<ArrayField
source="books"
storeKey="customTwo"
>
<Datagrid>
<TextField source="title" />
</Datagrid>
</ArrayField>
</Stack><ArrayField> creates a ListContext with the field value, so you can use any of the list context values in its children. This includes callbacks to sort, filter, and select items.
For instance, you can make the chips selectable as follows:
const SelectedChip = () => {
const { selectedIds, onToggleItem } = useListContext();
const record = useRecordContext();
return (
<ChipField
source="title"
clickable
onClick={() => {
onToggleItem(record.id);
}}
color={selectedIds.includes(record.id) ? 'primary' : 'default'}
/>
);
};
const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="title" />
<ArrayField source="tags">
<SingleFieldList linkType={false}>
<SelectedChip />
</SingleFieldList>
</ArrayField>
</SimpleShowLayout>
</Show>
)Tip: The selection logic uses the id field for each collection element, so the above example assumes that the tags field contains objects like { id: 123, name: 'bar' }.
Check the useListContext documentation for more information on the list context values.
If you need to render a custom collection (e.g. an array of tags ['dolor', 'sit', 'amet']), it's often simpler to write your own component:
import { useRecordContext } from 'react-admin';
const TagsField = () => {
const record = useRecordContext();
return (
<ul>
{record.tags.map(item => (
<li key={item.name}>{item.name}</li>
))}
</ul>
)
};