Home > Enterprise >  How to restrict the end date to not be earlier than the start date with the v-datetime-picker librar
How to restrict the end date to not be earlier than the start date with the v-datetime-picker librar

Time:06-07

I'm using vuetify's v-datetime-picker library to save the start and end date of an event. My code is the following:

<template>          
              <v-datetime-picker label="DateTime Start" okText="Accept" clearText="Clear" 
                                  :datePickerProps="{
                                  'min':actualDate,
                                  'max':'2022-12-31 24:59:59',
                                }" 
    v-model="meeting.meeting_date_start">
    </v-datetime-picker>
                             
               <v-datetime-picker  okText="Accept" clearText="Clear"  label="DateTime End" 
                                 :datePickerProps="{
                                  'min':dateInit,
                                  'max':'2022-12-31 24:59:59',
                                }"
                                  v-model="meeting.meeting_date_end"> 
                </v-datetime-picker>                                
    </template>
        <script>
        export default {
            data: function () {
            return {
              actualDate:'',
            }
            },
        computed: {
             dateInit:function(){
              return this.meeting.meeting_date_start.toLocaleString('sv',{timeZoneName:'short'}).substring(0,19).replace(' GMT','')
            },
          mounted(){
              this.getCurrentDate();
            },
        methods:{
        getCurrentDate(){
                      this.actualDate=new Date().toLocaleString('sv',{timeZoneName:'short'}).substring(0,19).replace(' GMT','')
                      console.log(this.actualDate)
                    },
        },
        }
        </script>

Put the same date but 2 hours before and I did not get an error even though it is not correct. I tried creating a computed property to set the minimum date equal to the start date but it doesn't work.

CodePudding user response:

Check this codesanbox I made: https://codesandbox.io/s/stack-72497203-datetimepicker-range-example-ri2o7d?file=/src/components/DateTimeExample.vue

You need to understand how vuetify-datetime-picker works, this is a custom component that combines three main vuetify's components in one: a v-text-field, a v-date-picker and a v-time-picker. You'll need to modify the library to fully achieve what you want.

If you check the documentation of the library you will find that you can customize the props of each vuetify component through the props: textFieldProps, datePickerProps and timePickerProps, respectively.

So what I did first here is create a props object for each component in my data block, these objects contains the props I want to share across all my datetime pickers:

data: () => ({
    today: new Date().toISOString(),
    dateEnds: null,
    dateStart: null, 
    textFieldProps: {         
       prependIcon: 'mdi-calendar',
       color: 'purple darken-3'
    },
    datePickerProps: {
       scrollable: true,
       color: 'purple darken-3'
    },
    timePickerProps: {
       scrollable: true,
       ampmInTitle: true,
       format: 'ampm',
       color: 'purple darken-3'
    }
}),

The v-datetime-picker library returns a javascript date object. The v-date-picker and v-time-picker have the props min and max that you can use to restrict the input. But these props expects to receive a string, not a date object.

To pass the correct strings formats to each min and max props I created a couple computed properties that use the date-fns library to give the format I need for each prop. The date-fns is a library that already comes in the node_modules so you can import it and use it out of the box. This is same library that the datetime picker component use internally to give format to the text in the v-text-field.

computed: {
    dateStartFormat() {
        if (this.dateStart) {
            return format(this.dateStart, 'yyyy-MM-dd')
        } else {
            return null
        }
    },
    dateEndsFormat() {
        if (this.dateEnds) {
            return format(this.dateEnds, 'yyyy-MM-dd')
        } else {
            return null
        }
    },
    timeStartFormat() {
        if (this.dateStart) {
            return format(this.dateStart, 'HH:mm')
        } else {
            return null
        }
    },
    timeEndsFormat() {
        if (this.dateEnds) {
            return format(this.dateEnds, 'HH:mm')
        } else {
            return null
        }
    },
}

Now that we have the correct strings formats for min and max props, you can pass them to your datetime pickers accordingly. In this case I set the props directly in each component and concatenated the global props with the help of the spread operator.

<v-col cols="6">
    <v-datetime-picker
    v-model="dateStart"
    label="Start"
    :text-field-props="textFieldProps"
    :date-picker-props="{
        min: today,
        max: dateEndsFormat,
        ...datePickerProps
    }"
    :time-picker-props="{
        max: timeEndsFormat,
        ...timePickerProps
    }"
    ok-text="Save"
    clear-text="Clear"
    time-format="HH:mm"
    >
    <template slot="dateIcon">
        <v-icon color="purple darken-4">mdi-calendar-month</v-icon>
    </template>
    <template slot="timeIcon">
        <v-icon color="purple darken-4">mdi-clock-outline</v-icon>
    </template>
    </v-datetime-picker>
</v-col>
<v-col cols="6">
    <v-datetime-picker
    v-model="dateEnds"
    label="Ends"
    :disabled="!dateStart"
    :text-field-props="textFieldProps"
    :date-picker-props="{
        min: dateStartFormat,
        ...datePickerProps
    }"
    :time-picker-props="{
        min: timeStartFormat,
        ...timePickerProps
    }"
    ok-text="Save"
    clear-text="Clear"
    time-format="HH:mm"
    >
    <template slot="dateIcon">
        <v-icon color="purple darken-4">mdi-calendar-month</v-icon>
    </template>
    <template slot="timeIcon">
        <v-icon color="purple darken-4">mdi-clock-outline</v-icon>
    </template>
    </v-datetime-picker>
</v-col>

You're almost there!, if you test the example in the codesanbox you will find that it works but it has a couple bugs, from here you'll need to create your own custom datepicker component to fully achieve what you need since the original library might lack of customization options or events.

This library offers a good starting point for making your own component, that's why you can see it has a lot of forks in github, from my own experience I stumble with it the past and also ended making my own version of it since I wanted to customize it a little bit more and extend the functionality of it.

If you don't want to mess with making an npm package, you can just simply copy the component code from the github repo right here. And modify it to your needs.

What's next? TODO

  1. If you tested the codesandbox, the min prop of the v-time-picker works kinda right, but if you choose a different date than the dateStartFormat the min property doesn't gets cleared. I would emit an even when the inner date of the v-date-picker gets setted to remove the min prop from the clock if the user specifies a different date than the dateStartFormat.
  2. The value of the v-model of the v-datetime-picker doesn't get setted if you don't click the "Save" button, but you can still click outside the dialog to close it, I would either set the dialog as persistent or execute the code of the save button when dialog close to fix this. This is an issue that already comes with the original library.
  3. You could add a few more props to customize the colors of tabs, buttons, etc.

I hope this helps you get a better understanding about how the component works and achieve what you want.

  • Related