typescriptvue.jsvuelidate

What type should I set to component prop of Vuelidate field?


Look, I have a view where I need to validate some fields. The main problem is that I want to pass prop to a InputValidationWrapper Component like v$.[keyField]. But I don't know what type to set.

SignInView.vue

<template>
    <div class="sign-in-view">
        <form @submit.prevent="onSubmit" class="sign-in-form">
            <div class="inputs-container">
                <InputValidationWrapper :validationField="v$.email" required email>
                    <BaseInput title="Email" v-model="formData.email" />
                </InputValidationWrapper>
            </div>
            <button type="submit">submit</button>
        </form>
    </div>
</template>

<script setup lang="ts">
import BaseInput from "@/components/inputs/BaseInput.vue";
import InputValidationWrapper from "@/components/validators/InputValidationWrapper.vue";

import useVuelidate from "@vuelidate/core";
import { required, email } from "@vuelidate/validators";
import { computed, reactive } from "vue";

const formData = reactive({
    email: "",
    password: "",
});

const validationRules = computed(() => {
    return {
        email: { required, email },
        password: { required },
    };
});
const v$ = useVuelidate(validationRules, formData);

const onSubmit = async () => {
    const result = await v$.value.$validate();
    if (!result) return;
    console.log("submit");
};
</script> 

InputValidationWrapper.vue

<template>
    <div class="input-wrapper">
        <slot />
        <div class="errors-block">
            <RequiredValidation
                :isDirty="validationField.$dirty"
                :isInvalid="validationField.required.$invalid"
                v-if="required" />
            <EmailValidation :isDirty="validationField.$dirty" :isInvalid="validationField.email.$invalid" v-if="email" />
        </div>
    </div>
</template>

<script setup lang="ts">
import RequiredValidation from "./RequiredValidation.vue";
import EmailValidation from "./EmailValidation.vue";
import type { NestedValidations } from "@vuelidate/core/index.js";

type PropsType = {
    validationField: NestedValidations; //???
    required?: boolean;
    email?: boolean;
};

defineProps<PropsType>();
</script>

As you can see I make new component for each error and pass a props there as simple boolean. But validationField.$dirty throws an error Property '$dirty' does not exist on type NestedValidations<ValidationArgs<unknown>, unknown>'. and the same thing with validationField.email.$invalid


Solution

  • You can define your own interface to pass the Vuelidate Validation:

    i.e.

    export interface VuelidateValidation {
      $errors: ErrorObject[];
      $error: boolean;
      $invalid: boolean;
      $dirty: boolean;
      $touch: () => void;
    }
    

    And then you just use that in your component:

    <script setup lang="ts">
    export interface Props {
      validation?: VuelidateValidation
    }
    const props = defineProps<Props>();
    const model = defineModel();
    </script>
    <template>
      <input type="text" v-model="model" @input="validation?.$touch" @blur="validation?.$touch" />
      <div v-if="validation?.$error">
        Something wrong here.
      </div>
    </template>
    

    When you use that component you can just pass your vuelidate validation property:

    <template>
      <MyComponent :validation="v$.email" />
    </template>