I created v-form
like this
...
If you use vue-class-component
with vue-property-decorator
you can do it like this:
Define in a types.ts
a new Type with the vuetify form functions:
export type VForm = Vue & {
validate: () => boolean;
resetValidation: () => boolean;
reset: () => void;
};
Then import in your component:
import { VForm } from "types";
import { Component, Ref} from "vue-property-decorator";
Use @Ref in your component to define the form:
export default class YourComponent extends Vue {
@Ref("form") readonly form!: VForm;
}
so in your methods you can use it like this:
this.form.validate();
this.form.resetValidation();
this.form.reset();
Couldn't comment on the accepted solution since I'm new to StackOverflow and wanted to provide my solution to this. I took the same initial step to investigate as OP and did a console.log(this.$ref.form)
, the output on the console is actually an array of [VueComponent] and validate()
function doesn't exist in that context.
I was able to access the validate()
function on the form by doing this.$ref.form[0].validate()
None of the answers did it. I was trying to get the validate then promise to work on a form.
As per comment
if you are building your vue component in typescript using
export default Vue.extend({})
then do
import { ValidationObserver, ValidationProvider, extend } from "vee-validate";
import { required } from "vee-validate/dist/rules";
import Vue, { VueConstructor } from "vue";
export default (Vue as VueConstructor<
Vue & {
$refs: {
form: InstanceType<typeof ValidationProvider>;
};
}
>).extend({
methods: {
saveEntity() {
if (this.loading) return;
console.log(this.entity);
this.$refs.form.validate().then(success => {
if (!success) {
console.log("not valid");
return;
}
console.log("valid");
});
}
}
})
This validates the ValidationObserver ref="form" just fine.
let form: any = this.$refs.form
if(form.validate){}
Simple:
(this.$refs.form as Vue & { validate: () => boolean }).validate()
Alternative (use this if you reference this.$refs.form
multiple times in your component):
computed: {
form(): Vue & { validate: () => boolean } {
return this.$refs.form as Vue & { validate: () => boolean }
}
} // Use it like so: this.form.validate()
Reusable (use this if you use the v-form
component multiple times across your application):
// In a TS file
export type VForm = Vue & { validate: () => boolean }
// In component, import `VForm`
computed: {
form(): VForm {
return this.$refs.form as VForm
}
}
In the Vue
template syntax, we can use the ref
attribute on a Vue
instance or a DOM element. If ref
is used in a v-for
loop, an array of Vue
instances or DOM elements is retreived.
This is why this.$refs
can either return Vue | Element | Vue[] | Element[]
.
In order for TypeScript
to know which type is being used, we need to cast the value.
We can either do:
(this.$refs.form as Vue).validate()
or (<Vue>this.$refs.form).validate()
We cast it to Vue
because v-form
is a Vue
instance (component) and not an Element
.
My personal preference is to create a computed property which returns the Vue
instance(s) or DOM element(s) already casted.
ie.
computed: {
form(): Vue {
return this.$refs.form as Vue
}
}
The v-form
instance has a validate
method that returns a boolean, so we need to use an intersection type literal:
computed: {
form(): Vue & { validate: () => boolean } {
return this.$refs.form as Vue & { validate: () => boolean }
}
}
Then we can use it like so: this.form.validate()
A better solution would be to create a type with the intersection so that it can be reused across multiple components.
export type VForm = Vue & { validate: () => boolean }
Then import it in the component:
computed: {
form(): VForm {
return this.$refs.form as VForm
}
}