Skip to content

Commit

Permalink
fix: batch and sort paths for safer unsets closes #4115
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed May 9, 2023
1 parent 9b50cad commit fe322a0
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/lucky-pears-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vee-validate': patch
---

batch unsets and sort paths unset order for safer unsets closes #4115
3 changes: 2 additions & 1 deletion packages/vee-validate/src/useField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ComponentInternalInstance,
onBeforeUnmount,
warn,
nextTick,
} from 'vue';
import { klona as deepCopy } from 'klona/full';
import { validate as validateValue } from './validate';
Expand Down Expand Up @@ -434,7 +435,7 @@ function _useField<TValue = unknown>(
pathState.id.splice(pathState.id.indexOf(field.id), 1);
}
} else {
form.unsetPathValue(path);
form.unsetPathValue(unravel(name));
}

form.removePathState(path, id);
Expand Down
17 changes: 16 additions & 1 deletion packages/vee-validate/src/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,23 @@ export function useForm<
return pathState as PathState<PathValue<TValues, TPath>> | undefined;
}

let UNSET_BATCH: Path<TValues>[] = [];
let PENDING_UNSET: Promise<void> | null;
function unsetPathValue<TPath extends Path<TValues>>(path: TPath) {
unsetPath(formValues, path);
UNSET_BATCH.push(path);
if (!PENDING_UNSET) {
PENDING_UNSET = nextTick(() => {
const sortedPaths = [...UNSET_BATCH].sort().reverse();
sortedPaths.forEach(p => {
unsetPath(formValues, p);
});

UNSET_BATCH = [];
PENDING_UNSET = null;
});
}

return PENDING_UNSET;
}

function makeSubmissionFactory(onlyControlled: boolean) {
Expand Down
43 changes: 42 additions & 1 deletion packages/vee-validate/tests/FieldArray.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineRule, useField } from '@/vee-validate';
import { Form, defineRule, useField } from '@/vee-validate';
import { toRef, ref, defineComponent } from 'vue';
import * as yup from 'yup';
import { mountWithHoc, setValue, getValue, dispatchEvent, flushPromises } from './helpers';
Expand Down Expand Up @@ -980,3 +980,44 @@ test('adding or removing fields should update form dirty correctly', async () =>
await flushPromises();
expect(dirty.textContent).toBe('false');
});

// #4115
test('removing fields with `v-if` should clean up their state properly', async () => {
const showFields = ref(true);
const formRef = ref<InstanceType<typeof Form>>();
const initialValues = {
users: [
{ name: 'test 1', amount: 123 },
{ name: 'test 2', amount: 567 },
],
};
mountWithHoc({
setup() {
return {
initialValues,
formRef,
showFields,
};
},
template: `
<VForm ref="formRef" :initial-values="initialValues">
<FieldArray name="users" v-slot="{ fields }">
<fieldset v-for="(field, idx) in fields" :key="field.key">
<legend>User #{{ idx }}</legend>
<template v-if="showFields">
<Field :name="'users[' + idx + '].name'" />
<Field :name="'users[' + idx + '].amount'" />
</template>
</fieldset>
</FieldArray>
</VForm>
`,
});

await flushPromises();
expect(formRef.value?.getValues()).toEqual(initialValues);
showFields.value = false;
await flushPromises();
expect(formRef.value?.getValues()).toEqual({});
});

0 comments on commit fe322a0

Please sign in to comment.