Vuelidate example
by pandigity
HTML
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuelidate.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/validators.min.js"></script>
<div id="vue">
<form @submit.prevent="submit">
<h1>Register</h1>
<v-field label="Username":v="$v.username">
<input v-model="username" @blur="$v.username.$touch()">
</v-field>
<v-field label="Email" :v="$v.email">
<input v-model="email" @blur="$v.email.$touch()">
</v-field>
<v-field label="Password" :v="$v.password" type="password">
<input v-model="password" type="password" @blur="$v.password.$touch()">
<template slot="note">
Must be at least 8 characters and contain a lowercase character, uppercase character and a number.
</template>
</v-field>
<v-field label="Repeat password" :v="$v.password2">
<input v-model="password2" type="password" @blur="$v.password2.$touch()">
</v-field>
<button type="submit" :class="{invalid:$v.$invalid}">Submit</button>
<button type="button" @click="reset">Reset</button>
</form>
<pre>{{$data}}</pre>
<pre>{{$v}}</pre>
</div>
SCSS
form{
padding:30px;
width:200px;
border:1px solid lightgrey;
}
h1{
margin-top:0px;
}
input{
display:block;
width:100%;
box-sizing:border-box;
border:1px solid lightgrey;
padding:5px;
}
button{
padding:5px 15px;
}
.field{
margin-bottom:10px;
&.required label::after{
content:'*';
color:red;
}
&.valid{
input{
border-color:green;
}
label::after{
color:green;
}
}
&.error{
color:red;
input{
border-color:red;
}
}
.note{
font-size:12px;
}
}
button.invalid{
opacity:0.5;
}
JavaScript
Vue.use(window.vuelidate.default)
//This is a reusable component for showing validation state and error messages for each field
Vue.component('v-field', {
template:`
<div class="field" :class="{error:v.$error, valid:!v.$invalid, required:v.$params.required}">
<label>{{label}}</label>
<slot></slot>
<div class="note">
<slot name="note"></slot>
</div>
<div>{{message}}</div>
</div>`,
props:['label', 'v'],
computed:{
message () {
if (this.v.$error) {
for (let key in this.$options.messages) {
if (this.v[key] === false) {
return this.$options.messages[key](this.v)
}
}
} else {
return null
}
},
model:{
get(){
return this.value
},
set(val){
this.$emit('input',val)
}
}
},
messages:{ //Add more messages here when you need, the key should be the same as the name of the validator
required: v => 'This field is required',
email: v => 'Must be a valid e-mail',
alphaNum: v => 'May only contain letters and numbers',
minLength: v => 'Must be at least ' + v.$params.minLength.min + ' characters',
goodPassword: v => '', //The password rules are always displayed, so no need to show a message
sameAs: v => 'Must be same as ' + v.$params.sameAs.eq
}
})
//$invalid is true when the field is invalid. $error is true when the field is invalid AND it has been $touched. This is useful so that we don't immediately show all fields as invalid before the user has had a chance to fill them out.
//And now we initialize Vue and the form
new Vue({
el:'#vue',
data(){
return {
username:'',
email:'',
password:'',
password2:''
}
},
methods:{
submit(){
this.$v.$touch()
if(this.$v.$invalid){
alert('All fields are not valid')
} else {
alert('Success!')
}
},
reset(){
Object.assign(this.$data, this.$options.data())
...