diff --git a/packages/ra-core/src/form/useInput.spec.tsx b/packages/ra-core/src/form/useInput.spec.tsx index a989b5bb5e9..603416bdb6e 100644 --- a/packages/ra-core/src/form/useInput.spec.tsx +++ b/packages/ra-core/src/form/useInput.spec.tsx @@ -17,6 +17,26 @@ const Input: FunctionComponent< return children(inputProps); }; +const InputWithCustomOnChange: FunctionComponent< + { + children: (props: ReturnType) => ReactElement; + } & InputProps & { setContextValue?: (value: string) => void } +> = ({ children, setContextValue, ...props }) => { + const { getValues } = useFormContext(); + + return ( + { + props.onChange(e); + setContextValue(getValues()[props.source]); + }} + > + {children} + + ); +}; + describe('useInput', () => { it('returns the props needed for an input', () => { let inputProps; @@ -106,6 +126,46 @@ describe('useInput', () => { expect(handleBlur).toHaveBeenCalled(); }); + it('custom onChange handler should have access to updated context input value', () => { + let targetValue, contextValue; + const handleChange = e => { + targetValue = e.target.value; + }; + const setContextValue = value => { + contextValue = value; + }; + + render( + +
+ + {({ id, field }) => ( + + )} + +
+
+ ); + const input = screen.getByLabelText('Title'); + + fireEvent.change(input, { + target: { value: 'Changed title' }, + }); + expect(targetValue).toBe('Changed title'); + expect(contextValue).toBe('Changed title'); + }); + describe('defaultValue', () => { it('applies the defaultValue when input does not have a value', () => { const onSubmit = jest.fn(); diff --git a/packages/ra-core/src/form/useInput.ts b/packages/ra-core/src/form/useInput.ts index 7a99e17dc60..adb494b4706 100644 --- a/packages/ra-core/src/form/useInput.ts +++ b/packages/ra-core/src/form/useInput.ts @@ -87,21 +87,21 @@ export const useInput = ( useApplyInputDefaultValues(props); const onBlur = useEvent((...event: any[]) => { + controllerField.onBlur(); if (initialOnBlur) { initialOnBlur(...event); } - controllerField.onBlur(); }); const onChange = useEvent((...event: any[]) => { - if (initialOnChange) { - initialOnChange(...event); - } const eventOrValue = (props.type === 'checkbox' && event[0]?.target?.value === 'on' ? event[0].target.checked : event[0]?.target?.value ?? event[0]) as any; controllerField.onChange(parse ? parse(eventOrValue) : eventOrValue); + if (initialOnChange) { + initialOnChange(...event); + } }); const field = {