Skip to content

Commit f8a82fc

Browse files
authored
fix: mark form dirty when object keys are deleted (#4710)
Fixes #4678 This fix has been co-authored by @SCBosch.
1 parent 193a96f commit f8a82fc

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

packages/vee-validate/src/utils/assertions.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ export function isPropPresent(obj: Record<string, unknown>, prop: string) {
108108
* Compares if two values are the same borrowed from:
109109
* https://github.com/epoberezkin/fast-deep-equal
110110
* We added a case for file matching since `Object.keys` doesn't work with Files.
111+
*
112+
* NB: keys with the value undefined are ignored in the evaluation and considered equal to missing keys.
111113
* */
112114
export function isEqual(a: any, b: any) {
113115
if (a === b) return true;
@@ -162,7 +164,13 @@ export function isEqual(a: any, b: any) {
162164
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
163165

164166
keys = Object.keys(a);
165-
length = keys.length;
167+
length = keys.length - countUndefinedValues(a, keys);
168+
169+
if (length !== Object.keys(b).length - countUndefinedValues(b, Object.keys(b))) return false;
170+
171+
for (i = length; i-- !== 0; ) {
172+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
173+
}
166174

167175
for (i = length; i-- !== 0; ) {
168176
// eslint-disable-next-line no-var
@@ -179,6 +187,17 @@ export function isEqual(a: any, b: any) {
179187
return a !== a && b !== b;
180188
}
181189

190+
function countUndefinedValues(a: any, keys: string[]) {
191+
let result = 0;
192+
for (let i = keys.length; i-- !== 0; ) {
193+
// eslint-disable-next-line no-var
194+
var key = keys[i];
195+
196+
if (a[key] === undefined) result++;
197+
}
198+
return result;
199+
}
200+
182201
export function isFile(a: unknown): a is File {
183202
if (!isClient) {
184203
return false;

packages/vee-validate/tests/useForm.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,32 @@ describe('useForm()', () => {
11361136
expect(form.meta.value.dirty).toBe(false);
11371137
});
11381138

1139+
// #4678
1140+
test('form is marked as dirty when key is removed', async () => {
1141+
let form!: FormContext<any>;
1142+
mountWithHoc({
1143+
setup() {
1144+
form = useForm({
1145+
initialValues: {
1146+
fname: {
1147+
key1: 'value1',
1148+
key2: 'value2',
1149+
},
1150+
},
1151+
});
1152+
1153+
useField('fname');
1154+
1155+
return {};
1156+
},
1157+
template: `<div></div>`,
1158+
});
1159+
1160+
form.setFieldValue('fname', { key1: 'value1' });
1161+
await flushPromises();
1162+
expect(form.meta.value.dirty).toBe(true);
1163+
});
1164+
11391165
describe('error paths can have dot or square bracket for the same field', () => {
11401166
test('path is bracket, mutations are dot', async () => {
11411167
let field!: FieldContext<unknown>;

0 commit comments

Comments
 (0)