Vuelidate Date And Time Validation Example Tutorial

Vuelidate Date And Time Validation Example

Let’s make 3 examples of validation date and time in Vue 3 using the Vue.js model validation library Vuelidate. In the last example, we will use the Moment.js package.

I used to think that validating dates in javascript is difficult, but after I learned Vuelidate and Moment.js my thoughts changed for the better. so I wanted to make this short tutorial for helping other developers.

We will create 3 examples the first example is for comparing and validating dates, The second example is for date-time validation, and the last one is for validating date and time in minutes so we will use moment.js for a better experience and easy coding. Let’s get started

To install the packages use

npm install @vuelidate/core @vuelidate/validators

// OR

yarn add @vuelidate/core @vuelidate/validators
npm install moment --save


// OR

yarn add moment           

Vuelidate Date Validation

Let’s say we want to make a reservation, so we will have a start date input and end date input and we should make sure that the start date after today and the end date after the start date.

here is the <template> and <script>

<template>
<section class="h-100 h-custom bg-light" >
    <div class="container py-5 h-100">
        <div class="row d-flex justify-content-center align-items-center h-100">
            <div class="col d-flex justify-content-center align-items-center">
                    
                <div class="card border-0 " style="min-width:350px; max-width:500px">
                    <div class="card-body">
                        <h3 class="mb-4">Reservation</h3>
                        <hr/>
                        <div v-if="v$.$errors.length > 0" class="alert alert-danger" role="alert">
                            <ul>
                                <li
                                    v-for="error of v$.$errors"
                                    :key="error.$uid"
                                    >
                                    <strong>{{ error.$validator }}</strong>
                                    <small> on property </small>
                                    <strong>{{ error.$property }}</strong>
                                    <small> says: </small>
                                    <strong>{{ error.$message }}</strong>
                                </li>
                            </ul>
                        </div>
                        <form @submit="onSubmit">
                      
                          
                            <!-- Input--------------------->
                            <div class="mb-3">
                                <label class="form-label">Start date</label>
                                <input type="date" step="1" class="form-control"
                                    v-model.trim="form.startDate"
                                    @input="setTouched('startDate')"
                                    :class="v$.form.startDate.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.startDate.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
                            <!-- Input--------------------->
                            <div class="mb-3">
                                <label class="form-label">End Date</label>
                                <input type="date" class="form-control"
                                    v-model.trim="form.endDate"
                                    @input="setTouched('endDate')"
                                    :class="v$.form.endDate.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.endDate.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
     
                            <hr/>
                            <hr/>
                           
                            <div class="mb-3 text-center">
                                <button class="btn btn-primary" type="submit">Submit</button>
                            </div>
                            <hr/>

                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>
</template>
<script>
import useVuelidate from '@vuelidate/core'
import { required, helpers} from '@vuelidate/validators'
import moment from 'moment';

export default {
  name: 'Registration',
  setup() {
    return { v$: useVuelidate() }
  },
  data() {
    return {
      form: {
        startDate:null,
        endDate:null,
      },
    }
  },
  validations() {
        return {
          form: {
            startDate: {
                required,
                minValue: helpers.withMessage('End date must be after today', value => {
                    console.log(value)
                    return new Date(value) > new Date()
                }),   
            },
            endDate: {
                required,
                minValue: helpers.withMessage('End date must be after the start date', value => {
                    console.log(value)
                    return new Date(value) > new Date(this.form.startDate)
                }), 
                
            },
     }
  },
  methods: {
    setTouched(theModel) {
        if(theModel == 'startDate' || theModel == 'all'){this.v$.form.startDate.$touch()} 
        if(theModel == 'endDate' || theModel == 'all'){this.v$.form.endDate.$touch()}
    },
   async onSubmit(event) {
        event.preventDefault()
        this.setTouched('all');
        if (!this.v$.$invalid) 
        {
            alert('all Good')
        }
    },
  },
}
</script>

Vuelidate Date Time Validation

Let’s create the same example above but we will add time (Hours, Minutes, Seconds) to the validation comparison.

<!-- Input--------------------->
<div class="mb-3">
  <label class="form-label">Start Date Time</label>
  <input type="datetime-local" class="form-control"
    v-model.trim="form.startDateTime"
    @input="setTouched('startDateTime')"
    :class="v$.form.startDateTime.$error?'is-invalid':''"
  >
  <div v-for="error of v$.form.startDateTime.$errors" class="invalid-feedback"  :key="error.$uid"> 
    {{ error.$message }}
  </div>
</div>

<!-- Input--------------------->
<div class="mb-3">
  <label class="form-label">End Date Time</label>
    <input type="datetime-local" class="form-control"
     v-model.trim="form.endDateTime"
     @input="setTouched('endDateTime')"
     :class="v$.form.endDateTime.$error?'is-invalid':''"
    >
    <div v-for="error of v$.form.endDateTime.$errors" class="invalid-feedback"  :key="error.$uid"> 
      {{ error.$message }}
    </div>
</div>
  data() {
    return {
      form: {
        startDateTime:null,
        endDateTime:null,
      },
    }
  },
 validations() {
        return {
         form: {
  startDateTime: {
                required,
                minValue: helpers.withMessage('Start date time must be after today time', value => {
                    console.log(value)
                    return new Date(value) > new Date()
                }),   
            },
   endDateTime: {
                required,
                minValue: helpers.withMessage('End date time must be after the       start date time', value => {
                    console.log(value)
                    return new Date(value) > new Date(this.form.startDateTime)
                }), 
                
            },
          },
        }

     }  
  },
  methods: {
    setTouched(theModel) {

        if(theModel == 'startDateTime' || theModel == 'all'){this.v$.form.startDateTime.$touch()} 
        if(theModel == 'endDateTime' || theModel == 'all'){this.v$.form.endDateTime.$touch()}

   
    },

Vuelidate Date and Time Validation With Moment.js

My Favorite example so far. Let’s make the start date-time must be after 30 minutes from now as a minimum value and the end date time must be after the start date time as a maximum value of 120 minutes and a minimum of 45 minutes from the start date.

<script>
import useVuelidate from '@vuelidate/core'
import { required, helpers} from '@vuelidate/validators'
import moment from 'moment';
export default {
  name: 'Registration',
  setup() {
    return { v$: useVuelidate() }
  },

  data() {
    return {
      form: {
        startDateTimeIn30:null,
        endDateTimeIn30:null,

      },
    }
  },
  validations() {
        return {
          form: {
            startDateTimeIn30: {
                required,
                minValue: helpers.withMessage('Start date time must be after 30 minutes form now', value => {
                    let valueToCompare = moment().add(30, 'm').format()
                    return  moment(value).isAfter(valueToCompare)
                }),   
            },
            endDateTimeIn30: {
                required,
                minValue: helpers.withMessage('End date time must be after the start date time max 120 minutes, min 45 minutes from start date', value => {
                    let valueToCompareStart = moment().add(75, 'm').format() // 30 min start date + 45 min end date
                    let valueToCompareEnd = moment().add(150, 'm').format() // 30 min start date + 120 min end date
                    return  moment(value).isBetween(valueToCompareStart,valueToCompareEnd)
                }), 
                
            },
          },
        }
  },

  methods: {
    setTouched(theModel) {
        if(theModel == 'startDateTimeIn30' || theModel == 'all'){this.v$.form.startDateTimeIn30.$touch()} 
        if(theModel == 'endDateTimeIn30' || theModel == 'all'){this.v$.form.endDateTimeIn30.$touch()}    
    },
   async onSubmit(event) {
        event.preventDefault()
        this.setTouched('all');
        if (!this.v$.$invalid) 
        {
            alert('all Good')
        }
    },
  },
}
</script>
<!-- Input--------------------->
<div class="mb-3">
    <label class="form-label">Start Date Time Min 30 minutes from now</label>
    <input type="datetime-local" class="form-control"
        v-model.trim="form.startDateTimeIn30"
        @input="setTouched('startDateTimeIn30')"
        :class="v$.form.startDateTimeIn30.$error?'is-invalid':''"
    >
    <div v-for="error of v$.form.startDateTimeIn30.$errors" class="invalid-feedback"  :key="error.$uid"> 
        {{ error.$message }}
    </div>
</div>
<!-- Input--------------------->
<div class="mb-3">
    <label class="form-label">End Date Time Max 2 Hours Mim 45 Minutes Form  </label>
    <input type="datetime-local" class="form-control"
        v-model.trim="form.endDateTimeIn30"
        @input="setTouched('endDateTimeIn30')"
        :class="v$.form.endDateTimeIn30.$error?'is-invalid':''"
    >
    <div v-for="error of v$.form.endDateTimeIn30.$errors" class="invalid-feedback"  :key="error.$uid"> 
        {{ error.$message }}
    </div>
</div>

All Vuelidate Examples In One Component

<template>
<section class="h-100 h-custom bg-light" >
    <div class="container py-5 h-100">
        <div class="row d-flex justify-content-center align-items-center h-100">
            <div class="col d-flex justify-content-center align-items-center">
                    
                <div class="card border-0 " style="min-width:350px; max-width:500px">
                    <div class="card-body">
                        <h3 class="mb-4">Reservation</h3>
                        <hr/>
                        <div v-if="v$.$errors.length > 0" class="alert alert-danger" role="alert">
                            <ul>
                                <li
                                    v-for="error of v$.$errors"
                                    :key="error.$uid"
                                    >
                                    <strong>{{ error.$validator }}</strong>
                                    <small> on property </small>
                                    <strong>{{ error.$property }}</strong>
                                    <small> says: </small>
                                    <strong>{{ error.$message }}</strong>
                                </li>
                            </ul>
                        </div>
                        <form @submit="onSubmit">
                      
                          
                            <!-- Input--------------------->
                            <div class="mb-3">
                                <label class="form-label">Start date</label>
                                <input type="date" step="1" class="form-control"
                                    v-model.trim="form.startDate"
                                    @input="setTouched('startDate')"
                                    :class="v$.form.startDate.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.startDate.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
                            <!-- Input--------------------->
                            <div class="mb-3">
                                <label class="form-label">End Date</label>
                                <input type="date" class="form-control"
                                    v-model.trim="form.endDate"
                                    @input="setTouched('endDate')"
                                    :class="v$.form.endDate.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.endDate.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
                            <hr/>
                            <hr/>
                            <hr/>
                             <!-- Input--------------------->
                             <div class="mb-3">
                                <label class="form-label">Start Date Time</label>
                                <input type="datetime-local" class="form-control"
                                    v-model.trim="form.startDateTime"
                                    @input="setTouched('startDateTime')"
                                    :class="v$.form.startDateTime.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.startDateTime.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>

                             <!-- Input--------------------->
                             <div class="mb-3">
                                <label class="form-label">End Date Time</label>
                                <input type="datetime-local" class="form-control"
                                    v-model.trim="form.endDateTime"
                                    @input="setTouched('endDateTime')"
                                    :class="v$.form.endDateTime.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.endDateTime.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
                            <hr/>
                            <hr/>
                            <hr/>
                            <!-- Input--------------------->
                            <div class="mb-3">
                                <label class="form-label">Start Date Time Min 30 minutes from now</label>
                                <input type="datetime-local" class="form-control"
                                    v-model.trim="form.startDateTimeIn30"
                                    @input="setTouched('startDateTimeIn30')"
                                    :class="v$.form.startDateTimeIn30.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.startDateTimeIn30.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
                            <!-- Input--------------------->
                            <div class="mb-3">
                                <label class="form-label">End Date Time Max 2 Hours Mim 45 Minutes Form  </label>
                                <input type="datetime-local" class="form-control"
                                    v-model.trim="form.endDateTimeIn30"
                                    @input="setTouched('endDateTimeIn30')"
                                    :class="v$.form.endDateTimeIn30.$error?'is-invalid':''"
                                >
                                <div v-for="error of v$.form.endDateTimeIn30.$errors" class="invalid-feedback"  :key="error.$uid"> 
                                    {{ error.$message }}
                                </div>
                            </div>
                            <hr/>
                            <hr/>
                           
                            <div class="mb-3 text-center">
                                <button class="btn btn-primary" type="submit">Submit</button>
                            </div>
                            <hr/>

                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>
</template>
<script>
import useVuelidate from '@vuelidate/core'
import { required, helpers} from '@vuelidate/validators'
import moment from 'moment';

export default {
  name: 'Registration',
  setup() {
    return { v$: useVuelidate() }
  },
  data() {
    return {
      form: {
        startDate:null,
        endDate:null,
        startDateTime:null,
        endDateTime:null,
        startDateTimeIn30:null,
        endDateTimeIn30:null,

      },
    }
  },
  validations() {
        return {
          form: {
            startDate: {
                required,
                minValue: helpers.withMessage('End date must be after today', value => {
                    console.log(value)
                    return new Date(value) > new Date()
                }),   
            },
            endDate: {
                required,
                minValue: helpers.withMessage('End date must be after the start date', value => {
                    console.log(value)
                    return new Date(value) > new Date(this.form.startDate)
                }), 
                
            },
            startDateTime: {
                required,
                minValue: helpers.withMessage('Start date time must be after today time', value => {
                    console.log(value)
                    return new Date(value) > new Date()
                }),   
            },
            endDateTime: {
                required,
                minValue: helpers.withMessage('End date time must be after the start date time', value => {
                    console.log(value)
                    return new Date(value) > new Date(this.form.startDateTime)
                }), 
                
            },
            startDateTimeIn30: {
                required,
                minValue: helpers.withMessage('Start date time must be after 30 minutes form now', value => {
                    let valueToCompare = moment().add(30, 'm').format()
                    return  moment(value).isAfter(valueToCompare)
                }),   
            },
            endDateTimeIn30: {
                required,
                minValue: helpers.withMessage('End date time must be after the start date time max 120 minutes, min 45 minutes from start date', value => {
                    let valueToCompareStart = moment().add(75, 'm').format() // 30 min start date + 45 min end date
                    let valueToCompareEnd = moment().add(150, 'm').format() // 30 min start date + 120 min end date
                    return  moment(value).isBetween(valueToCompareStart,valueToCompareEnd)
                }), 
                
            },
          },
        }
  },
  methods: {
    setTouched(theModel) {
        if(theModel == 'startDate' || theModel == 'all'){this.v$.form.startDate.$touch()} 
        if(theModel == 'endDate' || theModel == 'all'){this.v$.form.endDate.$touch()}
        if(theModel == 'startDateTime' || theModel == 'all'){this.v$.form.startDateTime.$touch()} 
        if(theModel == 'endDateTime' || theModel == 'all'){this.v$.form.endDateTime.$touch()}
        if(theModel == 'startDateTimeIn30' || theModel == 'all'){this.v$.form.startDateTimeIn30.$touch()} 
        if(theModel == 'endDateTimeIn30' || theModel == 'all'){this.v$.form.endDateTimeIn30.$touch()}    
    },
   async onSubmit(event) {
        event.preventDefault()
        this.setTouched('all');
        if (!this.v$.$invalid) 
        {
            alert('all Good')
        }
    },
  },
}
</script>

That’s all, I hope that was useful for you, and if you want to learn more about Vuelidate Vue3 validation, here is a tutorial: Vue 3 Form Validation Example With Explanation

Leave a Reply

Your email address will not be published. Required fields are marked *