Search code examples
typescriptvuejs3vuelidatevuejs3-composition-api

Pass multiple parameters to own validation rule in Vue 3 with vuelidate


I have two fields "price" and "max_price". I want a validator, which calls every time I change the "price" field my lessThanMaxPrice validator rule.

With this setup everything is working:

<script setup lang="ts">

const lessThanMaxPrice = (price: number) => {
    const maxPrice = editItemForm.max_price;

    let isValid = true;

    if (price || maxPrice) {
        if (!maxPrice) {
            isValid = false;
        } else if (price && price >= maxPrice) {
            isValid = false;
        }
    }

    return isValid;
};

const editItemRules = computed(() => {
    return {
        price: {
            lessThanMaxPrice: helpers.withMessage(t('validation_errors.price_error'), lessThanMaxPrice),
        },
   }
});


let editItemForm = reactive({
    price: number|null,
    max_price: number|null
});

const editItemV$ = useVuelidate(editItemRules, editItemForm);

</script>

<template>
<v-text-field variant="outlined" hide-details="auto" id="p" type="number"
                        :valid="editItemV$.price.$error" :color="editItemV$.price.$error ? 'success' : ''"
                        :error-messages="editItemV$.price.$error ? editItemV$.price.$errors[0].$message.toString() : ''"
                        step="0.01" @change="editItemV$.price.$touch" v-model="editItemForm.price" />

<v-text-field variant="outlined" hide-details="auto" id="max_price" type="number"
                        :valid="editItemV$.max_price.$error" :color="editItemV$.max_price.$error ? 'success' : ''"
                        :error-messages="editItemV$.max_price.$error ? editItemV$.max_price.$errors[0].$message.toString() : ''"
                        step="0.01" @change="editItemV$.max_price.$touch" v-model="editItemForm.max_price" />

</template>

No I want to extract the lessThanMaxPrice-Function to an ValidationHelpers class, because I need this kind of validation in some other components:

export class ValidationHelpers {
    static lessThanMaxPrice(price: number | null, maxPrice: number | null) {
        let isValid = true;

        if (price || maxPrice) {
            if (!maxPrice) {
                isValid = false;
            } else if (price && price >= maxPrice) {
                isValid = false;
            }
        }

        return isValid;
    };
}

I dont know how to call the ValidationHelpers.lessThanMaxPrice function with parameters. This approach is not working:

const editItemRules = computed(() => {
    return {
        price: {
            lessThanMaxPrice: (value) => helpers.withMessage(t('validation_errors.price_error'), ValidationHelpers.lessThanMaxPriceTest(value, editItemForm.max_price)),
        }
   }
});

and VSCode throws the error:

Argument of type 'boolean' is not assignable to parameter of type 'ValidationRule<unknown>'.ts(2345)

I'm new to Vue / Vuelidate / Vuetify / TypeScript, so please be understanding :)


Solution

  • Of course, as always, once you ask the question, you come up with the answer.

    First I changed the @change handler to @input and @blur

    <v-text-field variant="outlined" hide-details="auto" id="price" type="number"
                            :valid="editItemV$.price.$error" :color="editItemV$.price.$error ? 'success' : ''"
                            :error-messages="editItemV$.price.$error ? editItemV$.price.$errors[0].$message.toString() : ''"
                            step="0.01" @input="editItemV$.price.$touch" @blur="editItemV$.price.$touch"
                            v-model="editItemForm.price" />
    

    However, the main problem was in my rules. With the following change everything works now:

    const editItemRules = computed(() => {
        return {
            price: {
                lessThanMaxPrice: helpers.withMessage(t('validation_errors.price_error'), (value: number | null) => ValidationHelpers.lessThanMaxPrice(value, editItemForm.max_price)),
            },
       }
    });