Form validation is a feature that’s not built into Vue.js. However, we still need this feature very much. In this article, we’ll look at how to add localization features with Vee-Validate. We also look at how to extract the input component code.
Lazily Import Locales
We can use the import
function to import a locale file from Vee-Validate.
For example, we can write:
import { localize } from 'vee-validate';
import(`vee-validate/dist/locale/fr.json`).then(locale => {
localize(code, locale);
});
Using Other i18n Libraries
Vee-Validate integrates with other i18n libraries. For instance, we can use the vue-i18n library with Vee-Validate.
We can write:
import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";
import { required } from "vee-validate/dist/rules";
import en from "vee-validate/dist/locale/en.json";
import VueI18n from "vue-i18n";
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: "en",
messages: {
en: {
validation: en.messages
}
}
});
extend("required", {
...required,
message: (_, values) => i18n.t("validation.required", values)
});
Vue.component("ValidationProvider", ValidationProvider);
Vue.config.productionTip = false;
new Vue({
i18n,
render: h => h(App)
}).$mount("#app");
We imported the messages from Vee-Validate.
Then we set them as the property of messages.en.validation
.
Then we use i18n.t
to translate the message.
Then we can write:
<template>
<div id="app">
<ValidationProvider name="name" rules="required" v-slot="{ errors }">
<input v-model="name" type="text" placeholder="name">
<span>{{ errors[0] }}</span>
</ValidationProvider>
<input type="submit" value="submit">
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
name: ""
};
}
};
</script>
to display the message.
Model-less Validation
We can validate inputted values without models.
For example, we can write:
main.js
import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";
import { required, image } from "vee-validate/dist/rules";
extend("required", required);
extend("image", image);
Vue.component("ValidationProvider", ValidationProvider);
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount("#app");
App.vue
<template>
<div id="app">
<ValidationProvider rules="required|image" name="file" v-slot="{ validate, errors }">
<input type="file" @change="validate">
<p>{{ errors[0] }}</p>
</ValidationProvider>
</div>
</template>
<script>
export default {
name: "App"
};
</script>
We imported the required
and image
rules in main.js
.
Then we used ValidationProvider
in the template.
We called the built-in validate
function to validate the file type when it’s changed.
We also have the name
prop on the ValidationProvider
.
Then we’ll see an error message if it’s not a valid image file.
Custom Component File Validation
Any component that emits an input
event can be validated by Vee-Validate.
The value is emitted with the input
event.
Value Synchronization
We can synchronize the value manually between what’s entered and what Vee-Validate sees with the syncValue
method.
For example, we can write:
this.$refs.provider.syncValue(newValue);
to set the value of the validation provider with newValue
.
Dynamic Rules
Rules can be applied dynamically.
We can put an expression in the rules
prop.
For example, we can write:
<template>
<div id="app">
<button @click="required = !required">{{required ? 'disable':'enable'}} required</button>
<br>
<ValidationProvider
:rules="`${required ? 'required' : ''}`"
name="value"
v-slot="{ validate, errors }"
>
<input v-model="value" type="text">
<p>{{ errors[0] }}</p>
</ValidationProvider>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
value: "",
required: true
};
}
};
</script>
Then when required
is false
, no validation will be done.
Otherwise, validation will be done.
Extracting Input Fields
We can extract input fields into their own component.
This way, we don’t have to repeatedly reference ValidationProvider
.
For example, we can write:
main.js
import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, ValidationObserver, extend } from "vee-validate";
import { required, image } from "vee-validate/dist/rules";
extend("required", required);
extend("image", image);
Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount("#app");
TextInput.vue
<template>
<ValidationProvider tag="div" :rules="rules" :name="name" :vid="vid" v-slot="{ errors }">
<input :type="type" v-model="currentValue">
<span>{{ errors[0] }}</span>
</ValidationProvider>
</template>
<script>
import { ValidationProvider } from "vee-validate";
export default {
name: "TextInput",
components: {
ValidationProvider
},
props: {
value: {
type: String,
default: ""
},
rules: {
type: [String, Object],
default: ""
},
name: {
type: String,
default: ""
},
vid: {
type: String,
default: undefined
},
type: {
type: String,
default: "text"
}
},
data: () => ({
currentValue: ""
}),
watch: {
currentValue(val) {
this.$emit("input", val);
}
}
};
</script>
The TextInput
component is the component with the form field logic.
It takes various props that are used to populate fields with the data we want.
The value entered with the input
event in the currentValue
watcher.
It also takes the value
prop.
Therefore, it can bind to v-model
.
App.vue
<template>
<div id="app">
<ValidationObserver v-slot="{ handleSubmit }">
<form @submit.prevent="handleSubmit(onSubmit)">
<TextInput v-model="firstName" name="First Name" rules="required"/>
<TextInput v-model="lastName" name="Last Name" rules="required"/>
<input type="submit" value="submit">
</form>
</ValidationObserver>
</div>
</template>
<script>
import TextInput from "./components/TextInput";
export default {
name: "App",
components: {
TextInput
},
data() {
return {
firstName: "",
lastName: ""
};
},
methods: {
onSubmit() {
alert("success");
}
}
};
</script>
Then we can use it in the form
element like any other input element.
Conclusion
We can add localization and extract form fields into a component.