Skip to content

Commit

Permalink
fix: properly track dirty around field mutations
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Feb 7, 2025
1 parent 1ec3ddd commit 6d25e1c
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 19 deletions.
11 changes: 9 additions & 2 deletions packages/core/src/useForm/formContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
IssueCollection,
DirtySchema,
} from '../types';
import { cloneDeep, normalizeArrayable } from '../utils/common';
import { cloneDeep, isEqual, normalizeArrayable } from '../utils/common';
import {
escapePath,
findLeaf,
Expand Down Expand Up @@ -94,6 +94,8 @@ export function createFormContext<TForm extends FormObject = FormObject, TOutput
}: FormContextCreateOptions<TForm, TOutput>): BaseFormContext<TForm> {
function setValue<TPath extends Path<TForm>>(path: TPath, value: PathValue<TForm, TPath> | undefined) {
setInPath(values, path, cloneDeep(value));
const oldValue = getFieldOriginalValue(path);
setDirty(path, !isEqual(oldValue, value));
}

function setTouched(value: boolean): void;
Expand Down Expand Up @@ -133,7 +135,12 @@ export function createFormContext<TForm extends FormObject = FormObject, TOutput
return !!findLeaf(dirty, l => l === true);
}

return !!getFromPath(dirty, path);
const value = getFromPath(dirty, path);
if (isObject(value)) {
return !!findLeaf(value, v => !!v);
}

return !!value;
}

function setDirty(value: boolean): void;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/useForm/useFormActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export function useFormActions<TForm extends FormObject = FormObject, TOutput ex

form.revertValues();
form.revertTouched();
form.revertDirty();
submitAttemptsCount.value = 0;
isSubmitAttempted.value = false;

Expand Down
10 changes: 0 additions & 10 deletions packages/core/src/useFormField/useFormField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,6 @@ export function useFormField<TValue = unknown>(opts?: Partial<FormFieldOptions<T
return !isEqual(fieldValue.value, form.getFieldOriginalValue(path));
});

// Keeps the form's dirty state in sync with the field's dirty state.
watch(isDirty, dirty => {
const path = getPath();
if (!path) {
return;
}

form?.setDirty(path, dirty);
});

if (opts?.syncModel ?? true) {
useSyncModel({
model: fieldValue,
Expand Down
19 changes: 12 additions & 7 deletions packages/core/src/useFormGroup/useFormGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
StandardSchema,
ValidationResult,
} from '../types';
import { isEqual, normalizeProps, useUniqId, warn, withRefCapture } from '../utils/common';
import { normalizeProps, useUniqId, warn, withRefCapture } from '../utils/common';
import { FormKey } from '../useForm';
import { useValidationProvider } from '../validation/useValidationProvider';
import { FormValidationMode } from '../useForm/formContext';
Expand Down Expand Up @@ -137,16 +137,16 @@ export function useFormGroup<TInput extends FormObject = FormObject, TOutput ext
}

function getValue(path?: string) {
return form?.getValue(prefixPath(path) ?? '');
if (!path) {
return form?.getValue(getPath()) ?? {};
}

return form?.getValue(prefixPath(path) || '');
}

const isValid = computed(() => getErrors().length === 0);
const isTouched = computed(() => form?.isTouched(getPath()) ?? false);
const isDirty = computed(() => {
const path = getPath();

return !isEqual(getValue(), form?.getFieldOriginalValue(path) ?? {});
});
const isDirty = computed(() => form?.isDirty(getPath()) ?? false);

function getError(path: string) {
return form?.getErrors(prefixPath(path) ?? '')?.[0];
Expand Down Expand Up @@ -236,6 +236,11 @@ export function useFormGroup<TInput extends FormObject = FormObject, TOutput ext
* Gets the group's value, passing in a path will return the value of that field.
*/
getValue,
/**
* Gets the values for the form group.
* @deprecated Use `getValue` without arguments instead.
*/
getValues: () => getValue(),
/**
* Gets the error for a given field.
*/
Expand Down
5 changes: 5 additions & 0 deletions packages/playground/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ const { isDirty } = useForm({

<InputText name="name" label="Your Name" />
<InputText name="account.name" label="Account Name" />

<FormGroup name="company" label="Company">
<InputText name="name" label="Account Name" />
<InputText name="address" label="Address" />
</FormGroup>
</div>
</template>
2 changes: 2 additions & 0 deletions packages/playground/src/components/FormGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<h2 v-bind="labelProps" class="text-2xl font-semibold text-white">{{ label }}</h2>
</div>

{{ { isDirty, isTouched } }}

<div class="flex flex-col gap-2 p-8">
<slot :display-error="displayError" :get-error="getError" :isTouched="isTouched" />
</div>
Expand Down

0 comments on commit 6d25e1c

Please sign in to comment.