Skip to content

Commit e2d672f

Browse files
authored
Merge pull request #6185 from marmelab/fix-usewarnwhenunsavedchanges
Fix useWarnWhenUsavedChanges and nested fields
2 parents 5379451 + b8d6c14 commit e2d672f

File tree

4 files changed

+67
-39
lines changed

4 files changed

+67
-39
lines changed

examples/simple/src/comments/CommentEdit.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const CommentEdit = props => {
7575
record={record}
7676
save={save}
7777
version={version}
78+
warnWhenUnsavedChanges
7879
>
7980
<TextInput disabled source="id" fullWidth />
8081
<ReferenceInput

examples/simple/src/tags/TagEdit.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
const TagEdit = props => (
1717
<>
1818
<Edit {...props}>
19-
<SimpleForm redirect="list">
19+
<SimpleForm redirect="list" warnWhenUnsavedChanges>
2020
<TextField source="id" />
2121
<TranslatableInputs locales={['en', 'fr']}>
2222
<TextInput source="name" validate={[required()]} />

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

+62-37
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ const FormBody = ({ handleSubmit }) => {
2020
aria-labelledby="firstname-label"
2121
component="input"
2222
/>
23+
<label id="author-label">Author</label>
24+
<Field
25+
name="author.name"
26+
aria-labelledby="author-label"
27+
component="input"
28+
/>
2329
<button type="button" onClick={onLeave}>
2430
Leave
2531
</button>
@@ -59,45 +65,64 @@ describe('useWarnWhenUnsavedChanges', () => {
5965
getByText('Submitted');
6066
});
6167

62-
it('should not warn when leaving form with submit button', () => {
63-
const { getByLabelText, getByText } = render(<App />);
64-
const input = getByLabelText('First Name') as HTMLInputElement;
65-
input.value = 'John Doe';
66-
fireEvent.click(getByText('Submit'));
67-
getByText('Submitted');
68-
});
68+
test.each([
69+
['simple', 'First Name'],
70+
['nested', 'Author'],
71+
])(
72+
'should not warn when leaving form with submit button after updating %s field',
73+
(_, field) => {
74+
const { getByLabelText, getByText } = render(<App />);
75+
fireEvent.change(getByLabelText(field), {
76+
target: { value: 'John Doe' },
77+
});
78+
fireEvent.click(getByText('Submit'));
79+
getByText('Submitted');
80+
}
81+
);
6982

70-
it('should warn when leaving form with unsaved changes', () => {
71-
// mock click on "cancel" in the confirm dialog
72-
window.confirm = jest.fn().mockReturnValue(false);
73-
const { getByLabelText, getByText, queryByText } = render(<App />);
74-
const input = getByLabelText('First Name') as HTMLInputElement;
75-
fireEvent.change(input, { target: { value: 'John Doe' } });
76-
fireEvent.click(getByText('Leave'));
77-
expect(window.confirm).toHaveBeenCalledWith(
78-
'ra.message.unsaved_changes'
79-
);
80-
// check that we're still in the form and that the unsaved changes are here
81-
expect((getByLabelText('First Name') as HTMLInputElement).value).toBe(
82-
'John Doe'
83-
);
84-
expect(queryByText('Somewhere')).toBeNull();
85-
});
83+
test.each([
84+
['simple', 'First Name'],
85+
['nested', 'Author'],
86+
])(
87+
'should warn when leaving form with unsaved changes after updating %s field',
88+
(_, field) => {
89+
// mock click on "cancel" in the confirm dialog
90+
window.confirm = jest.fn().mockReturnValue(false);
91+
const { getByLabelText, getByText, queryByText } = render(<App />);
92+
const input = getByLabelText(field) as HTMLInputElement;
93+
fireEvent.change(input, { target: { value: 'John Doe' } });
94+
fireEvent.click(getByText('Leave'));
95+
expect(window.confirm).toHaveBeenCalledWith(
96+
'ra.message.unsaved_changes'
97+
);
98+
// check that we're still in the form and that the unsaved changes are here
99+
expect(
100+
(getByLabelText('First Name') as HTMLInputElement).value
101+
).toBe('John Doe');
102+
expect(queryByText('Somewhere')).toBeNull();
103+
}
104+
);
86105

87-
it('should warn when leaving form with unsaved changes but accept override', () => {
88-
// mock click on "OK" in the confirm dialog
89-
window.confirm = jest.fn().mockReturnValue(true);
90-
const { getByLabelText, getByText, queryByText } = render(<App />);
91-
const input = getByLabelText('First Name') as HTMLInputElement;
92-
fireEvent.change(input, { target: { value: 'John Doe' } });
93-
fireEvent.click(getByText('Leave'));
94-
expect(window.confirm).toHaveBeenCalledWith(
95-
'ra.message.unsaved_changes'
96-
);
97-
// check that we're no longer in the form
98-
expect(queryByText('First Name')).toBeNull();
99-
getByText('Somewhere');
100-
});
106+
test.each([
107+
['simple', 'First Name'],
108+
['nested', 'Author'],
109+
])(
110+
'should warn when leaving form with unsaved changes but accept override',
111+
(_, field) => {
112+
// mock click on "OK" in the confirm dialog
113+
window.confirm = jest.fn().mockReturnValue(true);
114+
const { getByLabelText, getByText, queryByText } = render(<App />);
115+
const input = getByLabelText(field) as HTMLInputElement;
116+
fireEvent.change(input, { target: { value: 'John Doe' } });
117+
fireEvent.click(getByText('Leave'));
118+
expect(window.confirm).toHaveBeenCalledWith(
119+
'ra.message.unsaved_changes'
120+
);
121+
// check that we're no longer in the form
122+
expect(queryByText(field)).toBeNull();
123+
getByText('Somewhere');
124+
}
125+
);
101126

102127
afterAll(() => delete window.confirm);
103128
});

packages/ra-core/src/form/useWarnWhenUnsavedChanges.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect, useRef } from 'react';
22
import { useForm } from 'react-final-form';
33
import { useHistory } from 'react-router-dom';
4+
import get from 'lodash/get';
45

56
import { useTranslate } from '../i18n';
67

@@ -39,6 +40,7 @@ const useWarnWhenUnsavedChanges = (enable: boolean) => {
3940
const unsavedChanges = JSON.parse(
4041
window.sessionStorage.getItem('unsavedChanges')
4142
);
43+
4244
if (unsavedChanges) {
4345
Object.keys(unsavedChanges).forEach(key =>
4446
form.change(key, unsavedChanges[key])
@@ -61,7 +63,7 @@ const useWarnWhenUnsavedChanges = (enable: boolean) => {
6163
: formState.dirtyFields;
6264
const dirtyFieldValues = Object.keys(dirtyFields).reduce(
6365
(acc, key) => {
64-
acc[key] = formState.values[key];
66+
acc[key] = get(formState.values, key);
6567
return acc;
6668
},
6769
{}

0 commit comments

Comments
 (0)