Skip to content

Commit

Permalink
Merge pull request #7031 from marmelab/fix-selectinput-create-choice
Browse files Browse the repository at this point in the history
Fix `SelectInput` create optionText
  • Loading branch information
fzaninotto committed Dec 24, 2021
2 parents cbe0a35 + 290ffc1 commit 7a55998
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 24 deletions.
46 changes: 46 additions & 0 deletions packages/ra-ui-materialui/src/input/SelectInput.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,52 @@ describe('<SelectInput />', () => {
});
});

it('should support creation of a new choice with nested optionText', async () => {
const choices = [
{ id: 'programming', name: { en: 'Programming' } },
{ id: 'lifestyle', name: { en: 'Lifestyle' } },
{ id: 'photography', name: { en: 'Photography' } },
];
const newChoice = {
id: 'js_fatigue',
name: { en: 'New Kid On The Block' },
};

const { getByLabelText, getByRole, getByText, queryByText } = render(
<Form
validateOnBlur
onSubmit={jest.fn()}
render={() => (
<SelectInput
{...defaultProps}
choices={choices}
onCreate={() => {
choices.push(newChoice);
return newChoice;
}}
optionText="name.en"
/>
)}
/>
);

const input = getByLabelText(
'resources.posts.fields.language'
) as HTMLInputElement;
input.focus();
const select = getByRole('button');
fireEvent.mouseDown(select);

fireEvent.click(getByText('ra.action.create'));
await new Promise(resolve => setTimeout(resolve));
input.blur();

expect(
// The selector ensure we don't get the options from the menu but the select value
queryByText(newChoice.name.en, { selector: '[role=button]' })
).not.toBeNull();
});

it('should support creation of a new choice through the create element', async () => {
const choices = [...defaultProps.choices];
const newChoice = { id: 'js_fatigue', name: 'New Kid On The Block' };
Expand Down
51 changes: 27 additions & 24 deletions packages/ra-ui-materialui/src/input/SelectInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import { useCallback } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import MenuItem from '@material-ui/core/MenuItem';
import { TextFieldProps } from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';
Expand Down Expand Up @@ -144,9 +143,10 @@ export const SelectInput = (props: SelectInputProps) => {
`If you're not wrapping the SelectInput inside a ReferenceInput, you must provide the choices prop`
);

const { getChoiceText, getChoiceValue } = useChoices({
const { getChoiceText, getChoiceValue, getDisableValue } = useChoices({
optionText,
optionValue,
disableValue,
translateChoice,
});

Expand Down Expand Up @@ -201,6 +201,30 @@ export const SelectInput = (props: SelectInputProps) => {
onCreate,
optionText,
});

const createItem = create || onCreate ? getCreateItem() : null;
const finalChoices =
create || onCreate ? [...choices, createItem] : choices;

const renderMenuItem = useCallback(
choice => {
return choice ? (
<MenuItem
key={getChoiceValue(choice)}
value={getChoiceValue(choice)}
disabled={getDisableValue(choice)}
>
{renderMenuItemOption(
!!createItem && choice?.id === createItem.id
? createItem
: choice
)}
</MenuItem>
) : null;
},
[getChoiceValue, getDisableValue, renderMenuItemOption, createItem]
);

if (loading) {
return (
<Labeled
Expand All @@ -219,18 +243,6 @@ export const SelectInput = (props: SelectInputProps) => {
);
}

const renderCreateItem = () => {
if (onCreate || create) {
const createItem = getCreateItem();
return (
<MenuItem value={createItem.id} key={createItem.id}>
{createItem.name}
</MenuItem>
);
}
return null;
};

return (
<>
<ResettableTextField
Expand Down Expand Up @@ -273,16 +285,7 @@ export const SelectInput = (props: SelectInputProps) => {
{renderEmptyItemOption()}
</MenuItem>
) : null}
{choices.map(choice => (
<MenuItem
key={getChoiceValue(choice)}
value={getChoiceValue(choice)}
disabled={get(choice, disableValue)}
>
{renderMenuItemOption(choice)}
</MenuItem>
))}
{renderCreateItem()}
{finalChoices.map(renderMenuItem)}
</ResettableTextField>
{createElement}
</>
Expand Down

0 comments on commit 7a55998

Please sign in to comment.