Working with forms and Vuetify

Working with forms and Vuetify

Vuetify is a great component library, but it doesn't really guide you through the Javascript or Typescript part. I usually use Typescript and found a good way to handle forms throughout all components. It all start's with an interface:

export interface FormDefinition {
  valid: boolean;
  fields: {
    [key: string]: any;
  };
  rules?: {
    [key: string]: any;
  };
}

With every component I'm creating, I will extend the FormDefinition with a custom Form interface:

interface Form extends FormDefinition {
  fields: {
    firstName: string;
    ...
  },
  rules: {
    firstName: ((message?: string) => {})[];
    ...
  }
}

The rules are functions which I put into a form-rules.ts and import when needed. For example this is a rule to check if a form field is required:

export function requiredRule(message = 'Dieses Feld muss gefüllt sein'): (value: any) => boolean|string {
  return (value) => (!!value || value === 0) || message;
}

This way I only have write those rules once and can use them everywhere. A full implementation of the form in a component would look like this:

@Component
export default class CreateEditUserDialogComponent {

  form: Form = {
    valid: false,
    fields: {
      email: '',
      firstName: '',
      lastName: ''
    },
    rules: {
      email: [
        requiredRule(),
        emailRule()
      ],
      firstName: [
        requiredRule()
      ],
      lastName: [
        requiredRule()
      ]
    }
  };
  
  ...
}

Within the template I will have highlighting and error spotting by the IDE:

<v-form ref="form" v-model="form.valid" @submit.prevent="onSubmit">
  <v-card-text>
    <v-row>
      <v-col cols="12" sm="6">
        <v-text-field v-model="form.fields.firstName" label="First name" :rules="form.rules.firstName" />
      </v-col>
      <v-col cols="12" sm="6">
        <v-text-field v-model="form.fields.lastName" label="Last name" :rules="form.rules.lastName" />
      </v-col>
    </v-row>
    <v-row>
      <v-col cols="12" sm="6">
        <v-text-field type="email" v-model="form.fields.email" label="Email" :rules="form.rules.email" />
      </v-col>
    </v-row>
  </v-card-text>

  <v-card-actions>
    <v-spacer></v-spacer>
    <v-btn text @click="hide()">
      Cancel
    </v-btn>
    <v-btn type="submit" color="primary" :disabled="!form.valid">
      Save
    </v-btn>
  </v-card-actions>
</v-form>

All rules are connected to the form and with the form.valid I can disable the submit button without having to use any kind of form state validation methods.

I hope this will help you with your Vuetify forms. Let me know if there is something that can be improved.