How can I access Vuetify v-form ref in VueJS using Composition API at <script setup>?
Asked Answered
H

2

9

I'm creating a form using Vuetify's v-form in Vue using their Composition API and <script setup>. Using v-form's rules, I've created a way to validate user input; however, once the form is submitted, I need to clear the form's fields. When the fields are reset (using empty strings), the form rules are triggered and validation errors appear. I would like to access v-form's built-in functions (e.g., clear()); however, I can't access this.$refs.form in <script setup>. How can I access these functions or just clear my form without triggering validation rule errors after submission?

Here is the script portion so far:

<script setup lang="ts">
import { ref, Ref } from 'vue'
import { Service } from '@/types/service'

const service: Ref<Service> = ref({ name: '', endpoint: '' })
const loading = ref(false)
const isValid = ref(true)

const register = () => {
  loading.value = true
  isValid.value = false
  clear()
  setTimeout(() => {
    loading.value = false
  }, 2000)
}

const clear = () => {
  service.value = { name: '', endpoint: '' }
}

const serviceNameRules = [
  (v: string) => !!v || 'Service name is required',
  (v: string) =>
    v.length <= 20 || 'Service name must be less than 20 characters',
]

const endpointRules = [
  (v: string) => v.length <= 100 || 'Endpoint must be less than 100 characters',
  (v: string) =>
    isURL(v) ||
    'Endpoint must have a valid URL format (i.e., "http://example.com")',
]

const isURL = (str: string) => {
  try {
    const url = new URL(str)
    return url.protocol === 'http:' || url.protocol === 'https:'
  } catch (_) {
    return false
  }
}
</script>

Here is my template form

<template>
  <v-card elevation="5">
    <v-progress-linear
      v-if="loading"
      class="position-absolute"
      style="z-index: 1"
      color="#0062B8"
      height="10"
      indeterminate
    />

    <v-card-title>Register New Service</v-card-title>
    <v-card-text>
      <v-form
        @submit.prevent="register()"
        v-model="isValid"
        ref="form"
        lazy-validation
      >
        <v-text-field
          v-model="service.name"
          label="Service Name"
          hint="e.g., 'service-pages'"
          :rules="serviceNameRules"
          required
        />
        <v-text-field
          v-model="service.endpoint"
          label="Endpoint"
          hint="https://www.example.com/page"
          :rules="endpointRules"
          required
        />
        <v-btn
          type="submit"
          color="#0062B8"
          style="color: white"
          :disabled="!isValid"
        >
          Register
        </v-btn>
      </v-form>
    </v-card-text>
  </v-card>
</template>
Hypertrophy answered 1/7, 2022 at 20:18 Comment(0)
R
7

Try to create a form ref inside your script which is automatically bound to ref="form":

<script setup lang="ts">
import { ref, Ref } from 'vue'
import { Service } from '@/types/service'

const service: Ref<Service> = ref({ name: '', endpoint: '' })
const loading = ref(false)
const isValid = ref(true)

const form=ref<HTMLFormElement>(null)

....
 // then use it like 
 if(form.value){
     form.value.reset()
  }
 //or
  form.value?.reset()
....

Rotary answered 1/7, 2022 at 20:23 Comment(4)
I've tried this but I encounter the TypeScript error that Property 'clear' does not exist on type 'never'.ts(2339)Hypertrophy
Try out const form=ref<any>(null) or const form=ref<HTMLFormElement>(null)Rotary
Great! I was able to use const form = ref<HTMLFormElement>() and, when using the correct function name (i.e., reset()) like this form.value?.reset(), I got my expected result! Thanks for the direction!Hypertrophy
Also, I was able to be more specific in my typings by importing import { VForm } from 'vuetify/lib/components/index' and using const form = ref<typeof VForm>()Hypertrophy
M
2

Since the question is specifically about getting a reference to a Vuetify VForm component, the correct approach is:

<template>
   <v-form ref="myForm">
       <!-- ... -->
   </v-form>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { VForm } from 'vuetify/components';

const myForm = ref<InstanceType<typeof VForm> | null>(null);

const myMethod = () => {
    // now you can call methods from the Vuetify API on the instance, e.g.
    myForm.value?.resetValidation();
};
</script>
Marielamariele answered 6/2 at 8:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.