Skip to content

Commit

Permalink
fix(#4075): mark whole form dirty is validate called
Browse files Browse the repository at this point in the history
  • Loading branch information
m0ksem committed Dec 8, 2023
1 parent b64cecb commit 36f668a
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 5 deletions.
2 changes: 1 addition & 1 deletion packages/ui/src/components/va-form/VaForm.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export const ValidateAndResetValidation: StoryFn = () => ({
components: { VaForm, VaInput, VaButton },
template: `
<va-form ref="form">
<va-input data-testid="input" :rules="[false]"/>
<va-input data-testid="input" :rules="[false]" stateful />
</va-form>
<va-button @click="$refs.form.validate()">
Validate
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/composables/useForm/useFormChild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const useFormChild = (context: FormFiled) => {

if (!formContext) {
return {
isFormDirty: ref(false),
isFormImmediate: ref(false),
doShowError: ref(true),
doShowErrorMessages: ref(true),
Expand All @@ -26,6 +27,7 @@ export const useFormChild = (context: FormFiled) => {
})

return {
isFormDirty: formContext.isFormDirty,
isFormImmediate: formContext.immediate,
doShowError: formContext.doShowError,
doShowErrorMessages: formContext.doShowErrorMessages,
Expand Down
12 changes: 10 additions & 2 deletions packages/ui/src/composables/useForm/useFormParent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const createFormContext = <Names extends string>(options: FormParentOptio
doShowError: computed(() => !options.hideErrors),
doShowErrorMessages: computed(() => !options.hideErrorMessages),
doShowLoading: computed(() => !options.hideLoading),
isFormDirty: ref(false),
registerField: (uid: number, field: FormFiled) => {
fields.value.set(uid, field as FormFiled<Names>)
},
Expand All @@ -34,7 +35,7 @@ export const useFormParent = <Names extends string = string>(options: FormParent

provide(FormServiceKey, formContext)

const { fields } = formContext
const { fields, isFormDirty } = formContext

const fieldNames = computed(() => fields.value.map((field) => unref(field.name)).filter(Boolean) as Names[])
const fieldsNamed = computed(() => fields.value.reduce((acc, field) => {
Expand All @@ -47,31 +48,38 @@ export const useFormParent = <Names extends string = string>(options: FormParent
}, {} as Record<Names, FormFiled['value']>))
const isValid = computed(() => fields.value.every((field) => unref(field.isValid)))
const isLoading = computed(() => fields.value.some((field) => unref(field.isLoading)))
const isDirty = computed(() => fields.value.some((field) => unref(field.isLoading)))
const isDirty = computed({
get () { return fields.value.some((field) => unref(field.isLoading)) || isFormDirty.value },
set (v) { isFormDirty.value = v },
})
const errorMessages = computed(() => fields.value.map((field) => unref(field.errorMessages)).flat())
const errorMessagesNamed = computed(() => fields.value.reduce((acc, field) => {
if (unref(field.name)) { acc[unref(field.name) as Names] = unref(field.errorMessages) }
return acc
}, {} as Record<Names, any>))

const validate = () => {
isDirty.value = true
// Validate each filed to get the error messages
return fields.value.reduce((acc, field) => {
return field.validate() && acc
}, true)
}

const validateAsync = () => {
isDirty.value = true
return Promise.all(fields.value.map((field) => field.validateAsync())).then((results) => {
return results.every(Boolean)
})
}

const reset = () => {
isDirty.value = false
fields.value.forEach((field) => field.reset())
}

const resetValidation = () => {
isDirty.value = false
fields.value.forEach((field) => field.resetValidation())
}

Expand Down
12 changes: 10 additions & 2 deletions packages/ui/src/composables/useValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export const useValidation = <V, P extends ExtractPropTypes<typeof useValidation
const resetValidation = () => {
computedError.value = false
computedErrorMessages.value = []
isDirty.value = false
}

const processResults = (results: any[]) => {
Expand Down Expand Up @@ -193,6 +194,7 @@ export const useValidation = <V, P extends ExtractPropTypes<typeof useValidation
doShowError,
doShowLoading,
isFormImmediate,
isFormDirty,
} = useFormChild({
isDirty,
isValid: computed(() => !computedError.value),
Expand All @@ -202,7 +204,11 @@ export const useValidation = <V, P extends ExtractPropTypes<typeof useValidation
validateAsync,
resetValidation,
focus,
reset,
reset: () => {
reset()
resetValidation()
isDirty.value = false
},
value: computed(() => options.value || props.modelValue),
name: toRef(props, 'name'),
})
Expand All @@ -212,7 +218,9 @@ export const useValidation = <V, P extends ExtractPropTypes<typeof useValidation
computedError: computed(() => {
// Hide error if component haven't been interacted yet
// Ignore dirty state if immediateValidation is true
if (!immediateValidation.value && !isDirty.value) { return false }
if (!isFormDirty.value) {
if (!immediateValidation.value && !isDirty.value) { return false }
}

return doShowError.value ? computedError.value : false
}),
Expand Down

0 comments on commit 36f668a

Please sign in to comment.