Skip to content

Commit 90b61fc

Browse files
committed
fix: use cloned value when setting field value closes #3991
1 parent 7fc5077 commit 90b61fc

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

packages/vee-validate/src/useForm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
404404
return;
405405
}
406406

407-
let newValue = value;
407+
let newValue = clonedValue;
408408
// Single Checkbox: toggles the field value unless the field is being reset then force it
409409
if (!isFieldGroup(fieldInstance) && fieldInstance.type === 'checkbox' && !force && !RESET_LOCK) {
410410
newValue = deepCopy(

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,7 +1964,7 @@ describe('<Form />', () => {
19641964
<Field id="password" name="password" rules="required" />
19651965
19661966
<span id="meta">{{ meta.valid ? 'valid' : 'invalid' }}</span>
1967-
<button type="button" @click="resetForm()">Reset</button>
1967+
<button type="button" @click="resetForm()">Reset</button>
19681968
</VForm>
19691969
`,
19701970
});
@@ -1990,7 +1990,7 @@ describe('<Form />', () => {
19901990
<Field id="password" name="password" rules="required" />
19911991
19921992
<span id="meta">{{ meta.valid ? 'valid' : 'invalid' }}</span>
1993-
<button type="button" @click="resetForm({ errors: { email: 'bad' } })">Reset</button>
1993+
<button type="button" @click="resetForm({ errors: { email: 'bad' } })">Reset</button>
19941994
</VForm>
19951995
`,
19961996
});
@@ -2194,7 +2194,7 @@ describe('<Form />', () => {
21942194
</Field>
21952195
21962196
<span id="meta">{{ meta.touched ? 'touched' : 'untouched' }}</span>
2197-
<button type="submit">Submit</button>
2197+
<button type="submit">Submit</button>
21982198
</VForm>
21992199
`,
22002200
});
@@ -2228,7 +2228,7 @@ describe('<Form />', () => {
22282228
<Field name="email" />
22292229
<span id="passwordError">{{ errors.password }}</span>
22302230
2231-
<button type="submit">Submit</button>
2231+
<button type="submit">Submit</button>
22322232
</VForm>
22332233
`,
22342234
});
@@ -2260,7 +2260,7 @@ describe('<Form />', () => {
22602260
<Field name="email" />
22612261
<span id="passwordError">{{ errors.password }}</span>
22622262
2263-
<button type="submit">Submit</button>
2263+
<button type="submit">Submit</button>
22642264
</VForm>
22652265
`,
22662266
});
@@ -2501,7 +2501,7 @@ describe('<Form />', () => {
25012501
},
25022502
template: `
25032503
<VForm>
2504-
<Field name="check" type="checkbox" v-model="value" value="CHECKED" />
2504+
<Field name="check" type="checkbox" v-model="value" value="CHECKED" />
25052505
</VForm>
25062506
`,
25072507
});
@@ -2531,8 +2531,8 @@ describe('<Form />', () => {
25312531
},
25322532
template: `
25332533
<VForm>
2534-
<Field name="name" type="text" v-model="value" />
2535-
<Field v-if="isHidden" name="name" type="text" v-model="value" />
2534+
<Field name="name" type="text" v-model="value" />
2535+
<Field v-if="isHidden" name="name" type="text" v-model="value" />
25362536
</VForm>
25372537
`,
25382538
});

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FieldMeta, FormContext, useField, useForm } from '@/vee-validate';
1+
import { FieldMeta, FormContext, FormMeta, useField, useForm } from '@/vee-validate';
22
import { mountWithHoc, setValue, flushPromises, runInSetup } from './helpers';
33
import * as yup from 'yup';
44
import { onMounted, Ref } from 'vue';
@@ -651,4 +651,48 @@ describe('useForm()', () => {
651651
await flushPromises();
652652
expect(meta.validated).toBe(false);
653653
});
654+
655+
// #3991
656+
test('initial value should not be mutable if nested field model is used', async () => {
657+
let model!: Ref<{ name: string }>;
658+
let formMeta!: Ref<FormMeta<{ field: { name: string } }>>;
659+
let reset!: () => void;
660+
661+
mountWithHoc({
662+
setup() {
663+
const { meta, resetForm } = useForm({
664+
initialValues: { field: { name: '1' } },
665+
validationSchema: yup.object({
666+
name: yup.string().required(),
667+
}),
668+
});
669+
670+
const field = useField<{ name: string }>('field');
671+
model = field.value;
672+
formMeta = meta;
673+
reset = resetForm;
674+
675+
return {};
676+
},
677+
template: `
678+
<div></div>
679+
`,
680+
});
681+
682+
await flushPromises();
683+
expect(formMeta.value.initialValues?.field.name).toBe('1');
684+
model.value.name = 'test';
685+
await flushPromises();
686+
expect(model.value).toEqual({ name: 'test' });
687+
expect(formMeta.value.initialValues?.field.name).toBe('1');
688+
reset();
689+
await flushPromises();
690+
expect(model.value).toEqual({ name: '1' });
691+
expect(formMeta.value.initialValues?.field.name).toBe('1');
692+
693+
model.value.name = 'test';
694+
await flushPromises();
695+
expect(model.value).toEqual({ name: 'test' });
696+
expect(formMeta.value.initialValues?.field.name).toBe('1');
697+
});
654698
});

0 commit comments

Comments
 (0)