Skip to content

Commit 7a55998

Browse files
authored
Merge pull request #7031 from marmelab/fix-selectinput-create-choice
Fix `SelectInput` create optionText
2 parents cbe0a35 + 290ffc1 commit 7a55998

File tree

2 files changed

+73
-24
lines changed

2 files changed

+73
-24
lines changed

packages/ra-ui-materialui/src/input/SelectInput.spec.tsx

+46
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,52 @@ describe('<SelectInput />', () => {
585585
});
586586
});
587587

588+
it('should support creation of a new choice with nested optionText', async () => {
589+
const choices = [
590+
{ id: 'programming', name: { en: 'Programming' } },
591+
{ id: 'lifestyle', name: { en: 'Lifestyle' } },
592+
{ id: 'photography', name: { en: 'Photography' } },
593+
];
594+
const newChoice = {
595+
id: 'js_fatigue',
596+
name: { en: 'New Kid On The Block' },
597+
};
598+
599+
const { getByLabelText, getByRole, getByText, queryByText } = render(
600+
<Form
601+
validateOnBlur
602+
onSubmit={jest.fn()}
603+
render={() => (
604+
<SelectInput
605+
{...defaultProps}
606+
choices={choices}
607+
onCreate={() => {
608+
choices.push(newChoice);
609+
return newChoice;
610+
}}
611+
optionText="name.en"
612+
/>
613+
)}
614+
/>
615+
);
616+
617+
const input = getByLabelText(
618+
'resources.posts.fields.language'
619+
) as HTMLInputElement;
620+
input.focus();
621+
const select = getByRole('button');
622+
fireEvent.mouseDown(select);
623+
624+
fireEvent.click(getByText('ra.action.create'));
625+
await new Promise(resolve => setTimeout(resolve));
626+
input.blur();
627+
628+
expect(
629+
// The selector ensure we don't get the options from the menu but the select value
630+
queryByText(newChoice.name.en, { selector: '[role=button]' })
631+
).not.toBeNull();
632+
});
633+
588634
it('should support creation of a new choice through the create element', async () => {
589635
const choices = [...defaultProps.choices];
590636
const newChoice = { id: 'js_fatigue', name: 'New Kid On The Block' };

packages/ra-ui-materialui/src/input/SelectInput.tsx

+27-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as React from 'react';
22
import { useCallback } from 'react';
33
import PropTypes from 'prop-types';
4-
import get from 'lodash/get';
54
import MenuItem from '@material-ui/core/MenuItem';
65
import { TextFieldProps } from '@material-ui/core/TextField';
76
import { makeStyles } from '@material-ui/core/styles';
@@ -144,9 +143,10 @@ export const SelectInput = (props: SelectInputProps) => {
144143
`If you're not wrapping the SelectInput inside a ReferenceInput, you must provide the choices prop`
145144
);
146145

147-
const { getChoiceText, getChoiceValue } = useChoices({
146+
const { getChoiceText, getChoiceValue, getDisableValue } = useChoices({
148147
optionText,
149148
optionValue,
149+
disableValue,
150150
translateChoice,
151151
});
152152

@@ -201,6 +201,30 @@ export const SelectInput = (props: SelectInputProps) => {
201201
onCreate,
202202
optionText,
203203
});
204+
205+
const createItem = create || onCreate ? getCreateItem() : null;
206+
const finalChoices =
207+
create || onCreate ? [...choices, createItem] : choices;
208+
209+
const renderMenuItem = useCallback(
210+
choice => {
211+
return choice ? (
212+
<MenuItem
213+
key={getChoiceValue(choice)}
214+
value={getChoiceValue(choice)}
215+
disabled={getDisableValue(choice)}
216+
>
217+
{renderMenuItemOption(
218+
!!createItem && choice?.id === createItem.id
219+
? createItem
220+
: choice
221+
)}
222+
</MenuItem>
223+
) : null;
224+
},
225+
[getChoiceValue, getDisableValue, renderMenuItemOption, createItem]
226+
);
227+
204228
if (loading) {
205229
return (
206230
<Labeled
@@ -219,18 +243,6 @@ export const SelectInput = (props: SelectInputProps) => {
219243
);
220244
}
221245

222-
const renderCreateItem = () => {
223-
if (onCreate || create) {
224-
const createItem = getCreateItem();
225-
return (
226-
<MenuItem value={createItem.id} key={createItem.id}>
227-
{createItem.name}
228-
</MenuItem>
229-
);
230-
}
231-
return null;
232-
};
233-
234246
return (
235247
<>
236248
<ResettableTextField
@@ -273,16 +285,7 @@ export const SelectInput = (props: SelectInputProps) => {
273285
{renderEmptyItemOption()}
274286
</MenuItem>
275287
) : null}
276-
{choices.map(choice => (
277-
<MenuItem
278-
key={getChoiceValue(choice)}
279-
value={getChoiceValue(choice)}
280-
disabled={get(choice, disableValue)}
281-
>
282-
{renderMenuItemOption(choice)}
283-
</MenuItem>
284-
))}
285-
{renderCreateItem()}
288+
{finalChoices.map(renderMenuItem)}
286289
</ResettableTextField>
287290
{createElement}
288291
</>

0 commit comments

Comments
 (0)