Skip to content

Commit 9060151

Browse files
committed
Accept reactElement in <ReferenceOneField emptyText>
1 parent 5aed217 commit 9060151

File tree

4 files changed

+103
-84
lines changed

4 files changed

+103
-84
lines changed

docs/ReferenceOneField.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ const BookShow = () => (
6363
| `link` | Optional | `string | Function` | `edit` | Target of the link wrapping the rendered child. Set to `false` to disable the link. |
6464
| `queryOptions` | Optional | [`UseQueryOptions`](https://tanstack.com/query/v5/docs/react/reference/useQuery) | `{}` | `react-query` client options |
6565
| `sort` | Optional | `{ field: String, order: 'ASC' or 'DESC' }` | `{ field: 'id', order: 'ASC' }` | Used to order referenced records |
66-
| `emptyContent` | Optional | `ReactNode` | - | Defines a content to be shown when a field has no value |
6766

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

@@ -79,20 +78,6 @@ For instance, if you want to render both the genre and the ISBN for a book:
7978
</ReferenceOneField>
8079
```
8180

82-
## `emptyContent`
83-
84-
Use `emptyContent` to display when the related record is empty.
85-
86-
```jsx
87-
<ReferenceOneField
88-
label="Details"
89-
reference="book_details"
90-
target="book_id"
91-
emptyContent={<CreateButton to="/book_details/create" />}
92-
>
93-
<TextField source="genre" /> (<TextField source="ISBN" />)
94-
</ReferenceOneField>
95-
```
9681

9782
## `emptyText`
9883

@@ -112,6 +97,19 @@ Use `emptyText` to customize the text displayed when the related record is empty
11297
</ReferenceOneField>
11398
```
11499

100+
`emptyText` also accepts a `ReactElement`.
101+
102+
```jsx
103+
<ReferenceOneField
104+
label="Details"
105+
reference="book_details"
106+
target="book_id"
107+
emptyText={<CreateButton to="/book_details/create" />}
108+
>
109+
<TextField source="genre" /> (<TextField source="ISBN" />)
110+
</ReferenceOneField>
111+
```
112+
115113
## `filter`
116114

117115
You can also use `<ReferenceOneField>` in a one-to-many relationship. In that case, the first record will be displayed. The `filter` prop becomes super useful in that case, as it allows you to select the appropriate record to display.

packages/ra-ui-materialui/src/field/ReferenceOneField.spec.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import { render, screen, waitFor } from '@testing-library/react';
2+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
33

44
import {
55
RecordRepresentation,
@@ -54,6 +54,10 @@ describe('ReferenceOneField', () => {
5454

5555
it('should render the "emptyContent" prop when the record is not found', async () => {
5656
render(<EmptyContent />);
57+
await waitFor(() => {
58+
expect(screen.queryAllByText('no detail')).toHaveLength(3);
59+
});
60+
fireEvent.click(screen.getByText('War and Peace'));
5761
await screen.findByText('Create');
5862
});
5963
});

packages/ra-ui-materialui/src/field/ReferenceOneField.stories.tsx

Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
CreateButton,
2828
Create,
2929
List,
30-
ListGuesser,
3130
Show,
3231
SimpleShowLayout,
3332
SimpleForm,
@@ -154,63 +153,78 @@ const dataProvider = fakeRestDataProvider({
154153
});
155154

156155
export const EmptyContent = () => (
157-
<TestMemoryRouter initialEntries={['/books/1/show']}>
158-
<AdminContext dataProvider={dataProvider} i18nProvider={i18nProvider}>
159-
<AdminUI>
160-
<Resource
161-
name="books"
162-
list={ListGuesser}
163-
show={() => (
164-
<Show>
165-
<SimpleShowLayout>
166-
<TextField source="id" />
167-
<TextField source="title" />
168-
<TextField source="year" />
169-
<TextField source="Genre" />
170-
<ReferenceOneField
171-
reference="book_details"
172-
target="book_id"
173-
label="ISBN"
174-
emptyContent={
175-
<CreateButton to="/book_details/create" />
176-
}
177-
>
178-
<TextField source="ISBN" />
179-
</ReferenceOneField>
180-
</SimpleShowLayout>
181-
</Show>
182-
)}
183-
/>
184-
<Resource
185-
name="book_details"
186-
list={() => (
187-
<List>
188-
<Datagrid>
189-
<TextField source="id" />
156+
<AdminContext dataProvider={dataProvider} i18nProvider={i18nProvider}>
157+
<AdminUI>
158+
<Resource
159+
name="books"
160+
list={() => (
161+
<List>
162+
<Datagrid>
163+
<TextField source="id" />
164+
<TextField source="title" />
165+
<TextField source="year" />
166+
<TextField source="Genre" />
167+
<ReferenceOneField
168+
reference="book_details"
169+
target="book_id"
170+
label="ISBN"
171+
emptyText="no detail"
172+
>
190173
<TextField source="ISBN" />
191-
<ReferenceField
192-
source="book_id"
193-
reference="books"
194-
/>
195-
</Datagrid>
196-
</List>
197-
)}
198-
create={() => (
199-
<Create>
200-
<SimpleForm>
201-
<TextInput source="ISBN" />
202-
<ReferenceInput
203-
source="book_id"
204-
reference="books"
205-
label="Book"
206-
/>
207-
</SimpleForm>
208-
</Create>
209-
)}
210-
/>
211-
</AdminUI>
212-
</AdminContext>
213-
</TestMemoryRouter>
174+
</ReferenceOneField>
175+
</Datagrid>
176+
</List>
177+
)}
178+
show={() => (
179+
<Show>
180+
<SimpleShowLayout>
181+
<TextField source="id" />
182+
<TextField source="title" />
183+
<TextField source="year" />
184+
<TextField source="Genre" />
185+
<ReferenceOneField
186+
reference="book_details"
187+
target="book_id"
188+
label="ISBN"
189+
emptyText={
190+
<CreateButton to="/book_details/create" />
191+
}
192+
>
193+
<TextField source="ISBN" />
194+
</ReferenceOneField>
195+
</SimpleShowLayout>
196+
</Show>
197+
)}
198+
/>
199+
<Resource
200+
name="book_details"
201+
list={() => (
202+
<List>
203+
<Datagrid>
204+
<TextField source="id" />
205+
<TextField source="ISBN" />
206+
<ReferenceField
207+
source="book_id"
208+
reference="books"
209+
/>
210+
</Datagrid>
211+
</List>
212+
)}
213+
create={() => (
214+
<Create>
215+
<SimpleForm>
216+
<TextInput source="ISBN" />
217+
<ReferenceInput
218+
source="book_id"
219+
reference="books"
220+
label="Book"
221+
/>
222+
</SimpleForm>
223+
</Create>
224+
)}
225+
/>
226+
</AdminUI>
227+
</AdminContext>
214228
);
215229

216230
export const EmptyWithTranslate = () => (

packages/ra-ui-materialui/src/field/ReferenceOneField.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactNode, useMemo } from 'react';
1+
import React, { ReactElement, ReactNode, useCallback, useMemo } from 'react';
22
import { UseQueryOptions } from '@tanstack/react-query';
33
import { Typography } from '@mui/material';
44
import {
@@ -39,7 +39,6 @@ export const ReferenceOneField = <
3939
reference,
4040
source = 'id',
4141
target,
42-
emptyContent,
4342
emptyText,
4443
sort,
4544
filter,
@@ -67,6 +66,16 @@ export const ReferenceOneField = <
6766
link,
6867
});
6968

69+
const renderEmptyItemOption = useCallback(() => {
70+
return typeof emptyText === 'string' ? (
71+
<Typography component="span" variant="body2">
72+
{emptyText && translate(emptyText, { _: emptyText })}
73+
</Typography>
74+
) : emptyText ? (
75+
emptyText
76+
) : null;
77+
}, [emptyText, translate]);
78+
7079
const context = useMemo<UseReferenceFieldControllerResult>(
7180
() => ({
7281
...controllerProps,
@@ -77,13 +86,7 @@ export const ReferenceOneField = <
7786
return !record ||
7887
(!controllerProps.isPending &&
7988
controllerProps.referenceRecord == null) ? (
80-
emptyContent ? (
81-
emptyContent
82-
) : emptyText ? (
83-
<Typography component="span" variant="body2">
84-
{emptyText && translate(emptyText, { _: emptyText })}
85-
</Typography>
86-
) : null
89+
renderEmptyItemOption()
8790
) : (
8891
<ResourceContextProvider value={reference}>
8992
<ReferenceFieldContextProvider value={context}>
@@ -100,15 +103,15 @@ export const ReferenceOneField = <
100103
export interface ReferenceOneFieldProps<
101104
RecordType extends RaRecord = RaRecord,
102105
ReferenceRecordType extends RaRecord = RaRecord,
103-
> extends Omit<FieldProps<RecordType>, 'source'> {
106+
> extends Omit<FieldProps<RecordType>, 'source' | 'emptyText'> {
104107
children?: ReactNode;
105108
reference: string;
106109
target: string;
107110
sort?: SortPayload;
108111
source?: string;
109112
filter?: any;
110113
link?: LinkToType<ReferenceRecordType>;
111-
emptyContent?: ReactNode;
114+
emptyText?: string | ReactElement;
112115
queryOptions?: Omit<
113116
UseQueryOptions<{
114117
data: ReferenceRecordType[];

0 commit comments

Comments
 (0)