I have a form with veevalidate. On form submit, the data is emitted to the parent, and then I need to reset the form. Following the veevalidate instructions, it should be possible to reset the form via $refs
.
My app is in TypeScript, and following the guides, my component looks like this:
<template>
<div>
<ValidationObserver v-slot="{ handleSubmit }" ref="form">
<form :model="form" @submit.prevent="handleSubmit(onSubmit)" novalidate>
<a-input-with-validation
:placeholder="placeholder"
:label="placeholder"
auto-complete="off"
name="comment"
type="text"
v-model="form.comment"
rules="required"
/>
<a-button-submit :translation-key="$t('dict.save')"/>
</form>
</ValidationObserver>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { ValidationObserver, ValidationProvider } from 'vee-validate'
import { OItemCommentFormChildOutput } from '@/components/organisms/forms/OItemCommentFormInterfaces'
import AInputWithValidation from '@/components/atoms/inputs/AInputWithValidation.vue'
import AButtonSubmit from '@/components/atoms/buttons/AButtonSubmit.vue'
@Component({
components: {
AButtonSubmit,
AInputWithValidation,
ValidationObserver,
ValidationProvider
}
})
export default class OItemCommentForm extends Vue {
@Prop()
comment?: string
@Prop({ default: true })
add!: boolean
$refs!: {
form: InstanceType<typeof ValidationObserver>;
}
placeholder!: string
form: OItemCommentFormChildOutput = {
comment: ''
}
mounted () {
this.$refs.form;
}
created () {
this.placeholder = String(this.add ? this.$t('dict.addComment') : this.$t('dict.editComment'))
this.form.comment = this.comment || ''
}
onSubmit () {
this.$emit('child-output', this.form as OItemCommentFormChildOutput)
// this.form.comment = ''
this.$refs.form.reset()
}
}
</script>
The a-input-with-validation
component code (from veevalidate):
<template>
<ValidationProvider
:vid="vid"
:name="nameAlt || name"
:rules="rules"
v-slot="{ errors, valid }"
>
<b-field
:label="label"
:prop="name"
v-bind="$attrs"
:auto-complete="autoComplete"
:type="{ 'is-danger': errors[0], 'is-success': valid }"
:message="errors"
>
<b-input
:name="name"
:type="type"
v-bind="$attrs"
:placeholder="placeholder"
v-model="innerValue"
:password-reveal="type === 'password'"
novalidate
/>
</b-field>
</ValidationProvider>
</template>
<style scoped>
.AInputWithValidation {}
</style>
<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import { ValidationObserver, ValidationProvider } from 'vee-validate'
@Component({
components: {
ValidationObserver,
ValidationProvider
}
})
export default class AInputWithValidation extends Vue {
@Prop({ required: true })
value!: any
@Prop({ required: true })
label!: string
@Prop({ required: true })
name!: string
@Prop({ default: 'off' })
autoComplete!: string
@Prop({ default: 'text' })
type!: string
@Prop()
nameAlt?: string
@Prop()
placeholder?: string
@Prop()
vid?: string
@Prop()
rules?: string
innerValue = ''
created () {
if (this.value) {
this.innerValue = this.value
}
}
@Watch('innerValue')
innerValueHandle (newVal) {
this.$emit('child-output', newVal)
this.$emit('input', newVal)
}
@Watch('value')
valueValueHandle (newVal) {
this.innerValue = newVal
}
}
</script>
The app compiles just fine, so seemingly no TS errors. On submit, the data is emitted correctly. But when I try to call the reset
method, nothing happens. The form is not reset, and the input value stays the same. If I also force the comment within the form to an empty string, this triggers the validator to display errors.
How can I reset the form after form submit and clear the contents of the form without triggering the validation errors?
(moving the ref="form"
onto the form tag does not do anything either :/)
ValidationObserver
's reset()
only resets the validation state, not the form fields. While the docs include a form-reset demo that manually clears the fields, you could alternatively invoke HTMLFormElement.reset()
on the <form>
element to reset the fields to their initial values. The <form>
element can be accessed from the SubmitEvent
's target:
export default class OItemCommentForm extends Vue {
async onSubmit(e) {
// Wait microtick for models to update before resetting validation state
await this.$nextTick()
this.$refs.form.reset()
// Reset form in next macrotick
setTimeout(() => e.target.reset())
}
}
The key is to reset the form in the next macrotick (via setTimeout
with a zero timeout).