Skip to content

Commit

Permalink
Make useInput hook return child's input.value when parent's enhanced …
Browse files Browse the repository at this point in the history
…input.value is undefined.

Closes #4203
Issue was caused by useField hook of final-form returning defaultValue of field as undefined (when it is not yet available in  state) while enhancing the parent input.

useInput hook of react-admin is considering same enhanced input with value undefined while rendering the children.
  • Loading branch information
prasanna214 committed Apr 4, 2020
1 parent 26a182d commit e63fc7a
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 6 deletions.
37 changes: 37 additions & 0 deletions packages/ra-core/src/form/useInput.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,43 @@ describe('useInput', () => {
expect(inputProps.meta).toBeDefined();
});

it('allows to override the value of enhanced input', () => {
let inputProps;
const enhancedInput: any = {
id: 'parent',
name: 'title',
isRequired: true,
};
const meta = {
touched: false,
};
render(
<Form
onSubmit={jest.fn()}
render={() => (
<Input
id="my-title"
source="title"
input={enhancedInput}
meta={meta}
resource="posts"
defaultValue={'overridden value'}
>
{props => {
inputProps = props;
return <div />;
}}
</Input>
)}
/>
);

expect(inputProps.id).toEqual('my-title');
expect(inputProps.input).toBeDefined();
expect(inputProps.input.value).toEqual('overridden value');
expect(inputProps.meta).toBeDefined();
});

it('allows to extend the input event handlers', () => {
const handleBlur = jest.fn();
const handleChange = jest.fn();
Expand Down
8 changes: 6 additions & 2 deletions packages/ra-core/src/form/useInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,14 @@ const useInput = ({

// If there is an input prop, this input has already been enhanced by final-form
// This is required in for inputs used inside other inputs (such as the SelectInput inside a ReferenceInput)
if (options.input) {
const enhancedInput = options.input;
if (enhancedInput) {
return {
id: id || source,
input: options.input,
input: {
...enhancedInput,
value: enhancedInput.value || input.value,
},
meta: options.meta,
isRequired: isRequired(validate),
};
Expand Down
6 changes: 2 additions & 4 deletions packages/ra-ui-materialui/src/input/ReferenceArrayInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,6 @@ const ReferenceArrayInput = ({
onChange,
onFocus,
validate,
parse,
format,
...props
}) => {
if (React.Children.count(children) !== 1) {
Expand All @@ -113,8 +111,8 @@ const ReferenceArrayInput = ({
onFocus,
source: props.source,
validate,
parse,
format,
parse: props.parse,
format: props.format,
});

const controllerProps = useReferenceArrayInputController({
Expand Down
25 changes: 25 additions & 0 deletions packages/ra-ui-materialui/src/input/ReferenceArrayInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,29 @@ describe('<ReferenceArrayInput />', () => {
queryByText(JSON.stringify({ touched: false, helperText: false }))
).not.toBeNull();
});

it('should pass format and parse props down to child component', () => {
let formatCallback, parseCallback;
const MyComponent = ({ parse, format }) => {
parseCallback = parse;
formatCallback = format;
return <div />;
};
const parse = jest.fn();
const format = jest.fn();
render(
<ReferenceArrayInputView
{...defaultProps}
allowEmpty
parse={parse}
format={format}
>
<MyComponent />
</ReferenceArrayInputView>
);
parseCallback('parse');
formatCallback('format');
expect(parse).toBeCalledWith('parse');
expect(format).toBeCalledWith('format');
});
});

0 comments on commit e63fc7a

Please sign in to comment.