Skip to content

Commit

Permalink
fix: double removal of path value FieldArray remove closes #4239
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed May 9, 2023
1 parent 9046308 commit 31090e0
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/eleven-forks-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vee-validate': patch
---

avoid double unset path with field array remove
7 changes: 6 additions & 1 deletion packages/vee-validate/src/types/forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export interface PathState<TValue = unknown> {
type: InputType;
multiple: boolean;
fieldsCount: number;
__flags: {
pendingUnmount: Record<string, boolean>;
};
validate?: FieldValidator;
}

Expand Down Expand Up @@ -248,6 +251,7 @@ export interface PrivateFormContext<TValues extends GenericObject = GenericObjec
getAllPathStates(): PathState[];
removePathState<TPath extends Path<TValues>>(path: TPath): void;
unsetPathValue<TPath extends Path<TValues>>(path: TPath): void;
markForUnmount(path: string): void;
}

export interface BaseComponentBinds<TValue = unknown> {
Expand All @@ -258,7 +262,7 @@ export interface BaseComponentBinds<TValue = unknown> {

export type PublicPathState<TValue = unknown> = Omit<
PathState<TValue>,
'bails' | 'label' | 'multiple' | 'fieldsCount' | 'validate' | 'id' | 'type'
'bails' | 'label' | 'multiple' | 'fieldsCount' | 'validate' | 'id' | 'type' | '__flags'
>;

export interface ComponentBindsConfig<TValue = unknown, TExtraProps extends GenericObject = GenericObject> {
Expand Down Expand Up @@ -313,6 +317,7 @@ export interface FormContext<TValues extends GenericObject = GenericObject, TOut
| 'setFieldInitialValue'
| 'unsetInitialValue'
| 'fieldArrays'
| 'markForUnmount'
| 'keepValuesOnUnmount'
> {
handleReset: () => void;
Expand Down
9 changes: 4 additions & 5 deletions packages/vee-validate/src/useField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ function _useField<TValue = unknown>(
const injectedForm = controlled ? injectWithSelf(FormContextKey) : undefined;
const form = (controlForm as PrivateFormContext | undefined) || injectedForm;
const name = lazyToRef(path);
let PENDING_UNMOUNT = false;

const validator = computed(() => {
const schema = unref(form?.schema);
Expand All @@ -137,7 +136,7 @@ function _useField<TValue = unknown>(
return normalizeRules(rulesValue);
});

const { id, value, initialValue, meta, setState, errors } = useFieldState(name, {
const { id, value, initialValue, meta, setState, errors, flags } = useFieldState(name, {
modelValue,
form,
bails,
Expand Down Expand Up @@ -184,7 +183,7 @@ function _useField<TValue = unknown>(
return validateCurrentValue('validated-only');
},
result => {
if (PENDING_UNMOUNT) {
if (flags.pendingUnmount[field.id]) {
return;
}

Expand Down Expand Up @@ -405,15 +404,15 @@ function _useField<TValue = unknown>(
});

onBeforeUnmount(() => {
PENDING_UNMOUNT = true;
const shouldKeepValue = unref(field.keepValueOnUnmount) ?? unref(form.keepValuesOnUnmount);
const path = unravel(name);
if (shouldKeepValue || !form) {
if (shouldKeepValue || !form || flags.pendingUnmount[field.id]) {
form?.removePathState(path);

return;
}

flags.pendingUnmount[field.id] = true;
const pathState = form.getPathState(path);
const matchesId =
Array.isArray(pathState?.id) && pathState?.multiple
Expand Down
1 change: 1 addition & 0 deletions packages/vee-validate/src/useFieldArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export function useFieldArray<TValue = unknown>(arrayPath: MaybeRef<string>): Fi
const newValue = [...pathValue];
newValue.splice(idx, 1);
const fieldPath = pathName + `[${idx}]`;
form.markForUnmount(fieldPath);
form.unsetInitialValue(fieldPath);
setInPath(form.values, pathName, newValue);
fields.value.splice(idx, 1);
Expand Down
5 changes: 4 additions & 1 deletion packages/vee-validate/src/useFieldState.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { computed, isRef, reactive, ref, Ref, unref, watch } from 'vue';
import { FieldMeta, FieldState, FieldValidator, InputType, MaybeRef, PrivateFormContext } from './types';
import { FieldMeta, FieldState, FieldValidator, InputType, MaybeRef, PrivateFormContext, PathState } from './types';
import { getFromPath, isEqual, normalizeErrorItem } from './utils';

export interface StateSetterInit<TValue = unknown> extends FieldState<TValue> {
Expand All @@ -11,6 +11,7 @@ export interface FieldStateComposable<TValue = unknown> {
path: MaybeRef<string>;
meta: FieldMeta<TValue>;
value: Ref<TValue>;
flags: PathState['__flags'];
initialValue: Ref<TValue>;
errors: Ref<string[]>;
setState(state: Partial<StateSetterInit<TValue>>): void;
Expand Down Expand Up @@ -62,6 +63,7 @@ export function useFieldState<TValue = unknown>(
value,
initialValue,
meta,
flags: { pendingUnmount: { [id]: false } },
errors,
setState,
};
Expand Down Expand Up @@ -101,6 +103,7 @@ export function useFieldState<TValue = unknown>(
errors,
meta: state,
initialValue,
flags: state.__flags,
setState,
};
}
Expand Down
23 changes: 20 additions & 3 deletions packages/vee-validate/src/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,21 +241,24 @@ export function useForm<
pathStateExists.multiple = true;
}

const id = FIELD_ID_COUNTER++;
if (Array.isArray(pathStateExists.id)) {
pathStateExists.id.push(FIELD_ID_COUNTER++);
pathStateExists.id.push(id);
} else {
pathStateExists.id = [pathStateExists.id, FIELD_ID_COUNTER++];
pathStateExists.id = [pathStateExists.id, id];
}

pathStateExists.fieldsCount++;
pathStateExists.__flags.pendingUnmount[id] = false;

return pathStateExists as PathState<TValue>;
}

const currentValue = computed(() => getFromPath(formValues, unravel(path)));
const pathValue = unravel(path);
const id = FIELD_ID_COUNTER++;
const state = reactive({
id: FIELD_ID_COUNTER++,
id,
path,
touched: false,
pending: false,
Expand All @@ -268,6 +271,9 @@ export function useForm<
type: config?.type || 'default',
value: currentValue,
multiple: false,
__flags: {
pendingUnmount: { [id]: false },
},
fieldsCount: 1,
validate: config?.validate,
dirty: computed(() => {
Expand Down Expand Up @@ -467,6 +473,16 @@ export function useForm<
}
}

function markForUnmount(path: string) {
return mutateAllPathState(s => {
if (s.path.startsWith(path)) {
keysOf(s.__flags.pendingUnmount).forEach(id => {
s.__flags.pendingUnmount[id] = true;
});
}
});
}

const formCtx: PrivateFormContext<TValues, TOutput> = {
formId,
values: formValues,
Expand Down Expand Up @@ -501,6 +517,7 @@ export function useForm<
removePathState,
initialValues: initialValues as Ref<TValues>,
getAllPathStates: () => pathStates.value,
markForUnmount,
};

/**
Expand Down

0 comments on commit 31090e0

Please sign in to comment.