Skip to content

Commit dd0e500

Browse files
authored
Merge pull request #8910 from WiXSL/fix-eh-exec-order
Fix custom input's onChange handlers should have access to updated context value
2 parents 0fa640f + caf4d46 commit dd0e500

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

packages/ra-core/src/form/useInput.spec.tsx

+60
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,26 @@ const Input: FunctionComponent<
1717
return children(inputProps);
1818
};
1919

20+
const InputWithCustomOnChange: FunctionComponent<
21+
{
22+
children: (props: ReturnType<typeof useInput>) => ReactElement;
23+
} & InputProps & { setContextValue?: (value: string) => void }
24+
> = ({ children, setContextValue, ...props }) => {
25+
const { getValues } = useFormContext();
26+
27+
return (
28+
<Input
29+
{...props}
30+
onChange={e => {
31+
props.onChange(e);
32+
setContextValue(getValues()[props.source]);
33+
}}
34+
>
35+
{children}
36+
</Input>
37+
);
38+
};
39+
2040
describe('useInput', () => {
2141
it('returns the props needed for an input', () => {
2242
let inputProps;
@@ -106,6 +126,46 @@ describe('useInput', () => {
106126
expect(handleBlur).toHaveBeenCalled();
107127
});
108128

129+
it('custom onChange handler should have access to updated context input value', () => {
130+
let targetValue, contextValue;
131+
const handleChange = e => {
132+
targetValue = e.target.value;
133+
};
134+
const setContextValue = value => {
135+
contextValue = value;
136+
};
137+
138+
render(
139+
<CoreAdminContext dataProvider={testDataProvider()}>
140+
<Form onSubmit={jest.fn()}>
141+
<InputWithCustomOnChange
142+
source="title"
143+
resource="posts"
144+
onChange={handleChange}
145+
setContextValue={setContextValue}
146+
defaultValue=""
147+
>
148+
{({ id, field }) => (
149+
<input
150+
type="text"
151+
id={id}
152+
aria-label="Title"
153+
{...field}
154+
/>
155+
)}
156+
</InputWithCustomOnChange>
157+
</Form>
158+
</CoreAdminContext>
159+
);
160+
const input = screen.getByLabelText('Title');
161+
162+
fireEvent.change(input, {
163+
target: { value: 'Changed title' },
164+
});
165+
expect(targetValue).toBe('Changed title');
166+
expect(contextValue).toBe('Changed title');
167+
});
168+
109169
describe('defaultValue', () => {
110170
it('applies the defaultValue when input does not have a value', () => {
111171
const onSubmit = jest.fn();

packages/ra-core/src/form/useInput.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,21 @@ export const useInput = <ValueType = any>(
8787
useApplyInputDefaultValues(props);
8888

8989
const onBlur = useEvent((...event: any[]) => {
90+
controllerField.onBlur();
9091
if (initialOnBlur) {
9192
initialOnBlur(...event);
9293
}
93-
controllerField.onBlur();
9494
});
9595

9696
const onChange = useEvent((...event: any[]) => {
97-
if (initialOnChange) {
98-
initialOnChange(...event);
99-
}
10097
const eventOrValue = (props.type === 'checkbox' &&
10198
event[0]?.target?.value === 'on'
10299
? event[0].target.checked
103100
: event[0]?.target?.value ?? event[0]) as any;
104101
controllerField.onChange(parse ? parse(eventOrValue) : eventOrValue);
102+
if (initialOnChange) {
103+
initialOnChange(...event);
104+
}
105105
});
106106

107107
const field = {

0 commit comments

Comments
 (0)