Skip to content

Commit 2fef6ab

Browse files
authored
Merge pull request #8275 from marmelab/fix-savebutton-state
Fix improve SaveButton enable state
2 parents 4357dd6 + 8d36514 commit 2fef6ab

File tree

4 files changed

+44
-6
lines changed

4 files changed

+44
-6
lines changed

packages/ra-ui-materialui/src/button/SaveButton.spec.tsx

+39-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ import {
1212
import { SaveButton } from './SaveButton';
1313
import { SimpleForm, Toolbar } from '../form';
1414
import { Edit } from '../detail';
15-
import { TextInput } from '../input';
15+
import {
16+
TextInput,
17+
ArrayInput,
18+
SimpleFormIterator,
19+
NumberInput,
20+
} from '../input';
1621
import { AdminContext } from '../AdminContext';
1722

1823
const invalidButtonDomProps = {
@@ -400,4 +405,37 @@ describe('<SaveButton />', () => {
400405
)
401406
);
402407
});
408+
409+
it('should not be enabled if no inputs have changed', async () => {
410+
render(
411+
<AdminContext dataProvider={testDataProvider()}>
412+
<SimpleForm
413+
resource="myresource"
414+
onSubmit={jest.fn}
415+
defaultValues={{
416+
test: 'test',
417+
}}
418+
>
419+
<TextInput source="test" />
420+
<ArrayInput resource="foo" source="arr">
421+
<SimpleFormIterator>
422+
<NumberInput source="id" />
423+
</SimpleFormIterator>
424+
</ArrayInput>
425+
</SimpleForm>
426+
</AdminContext>
427+
);
428+
429+
const testInput = screen.getByLabelText(
430+
'resources.myresource.fields.test'
431+
);
432+
fireEvent.focus(testInput);
433+
fireEvent.blur(testInput);
434+
435+
await waitFor(() =>
436+
expect(screen.getByLabelText('ra.action.save')['disabled']).toEqual(
437+
true
438+
)
439+
);
440+
});
403441
});

packages/ra-ui-materialui/src/button/SaveButton.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ export const SaveButton = <RecordType extends RaRecord = any>(
6565
const translate = useTranslate();
6666
const form = useFormContext();
6767
const saveContext = useSaveContext();
68-
const { isDirty, isValidating, isSubmitting } = useFormState();
68+
const { dirtyFields, isValidating, isSubmitting } = useFormState();
69+
// useFormState().isDirty might differ from useFormState().dirtyFields (https://github.com/react-hook-form/react-hook-form/issues/4740)
70+
const isDirty = Object.keys(dirtyFields).length > 0;
6971
// Use form isDirty, isValidating and form context saving to enable or disable the save button
7072
// if alwaysEnable is undefined
7173
const disabled = valueOrDefault(

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ describe('<DateTimeInput />', () => {
223223
const onSubmit = jest.fn();
224224
render(
225225
<AdminContext dataProvider={testDataProvider()}>
226-
<SimpleForm onSubmit={onSubmit}>
226+
<SimpleForm mode="onBlur" onSubmit={onSubmit}>
227227
<DateTimeInput
228228
{...defaultProps}
229229
validate={required()}
@@ -245,7 +245,6 @@ describe('<DateTimeInput />', () => {
245245
target: { value: '' },
246246
});
247247
fireEvent.blur(input);
248-
fireEvent.click(screen.getByText('ra.action.save'));
249248
await waitFor(() => {
250249
expect(
251250
screen.queryByText('ra.validation.required')

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ describe('<TimeInput />', () => {
213213
const onSubmit = jest.fn();
214214
render(
215215
<AdminContext dataProvider={testDataProvider()}>
216-
<SimpleForm onSubmit={onSubmit}>
216+
<SimpleForm mode="onBlur" onSubmit={onSubmit}>
217217
<TimeInput {...defaultProps} validate={required()} />
218218
</SimpleForm>
219219
</AdminContext>
@@ -232,7 +232,6 @@ describe('<TimeInput />', () => {
232232
target: { value: '' },
233233
});
234234
fireEvent.blur(input);
235-
fireEvent.click(screen.getByText('ra.action.save'));
236235
await waitFor(() => {
237236
expect(
238237
screen.queryByText('ra.validation.required')

0 commit comments

Comments
 (0)