Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change Vuetify calendar date format

I am attempting to enable inputted events on the following Vuetify calendar:

https://github.com/vuetifyjs/vuetify/blob/master/packages/docs/src/examples/calendars/complex/events.vue.

I have set up my calendar to accept inputted data submitted in a form, including name, details, start, end, color. When I submit the form, an error occurs saying that

the start and end properties are required on all events to be a valid timestamp in the format YYYY-MM-DD.

I am using type="date" in the start and end input fields, which render the dates in the MM-DD-YYYY. I tried using the Vuetify date picker instead in order to get the fields to render in YYYY-MM-DD format, but to no avail. How can I reconfigure this calendar to instead accept MM-DD-YYYY format for dates?

CALENDAR MODIFIED:

moment added to function

      async addEvent () {
        this.start = await new Date(this.start).toISOString().substring(0,10)
        this.end =  await new Date(this.end).toISOString().substring(0,10)
        this.events.push({name: this.name})
        this.events.push({details: this.details})
        this.events.push({start: this.start})
        this.events.push({end: this.end})
        this.events.push({color: this.color})
      },

Full Code

<template>
  <v-row class="fill-height">
    <v-col>
      <v-sheet height="64">
        <v-toolbar flat color="white">
          <v-btn outlined class="mr-4" @click="setToday">
            Today
          </v-btn>
          <v-btn fab text small @click="prev">
            <v-icon small>mdi-chevron-left</v-icon>
          </v-btn>
          <v-btn fab text small @click="next">
            <v-icon small>mdi-chevron-right</v-icon>
          </v-btn>
          <v-btn
            color="primary"
            dark
            @click.stop="dialog = true"
          >
            New Event
          </v-btn>
          <v-toolbar-title>{{ title }}</v-toolbar-title>
          <div class="flex-grow-1"></div>
        </v-toolbar>
      </v-sheet>

      <v-dialog v-model="dialog" max-width="500">
        <v-card>
          <v-container>
            <v-form @submit.prevent="addEvent">
              <v-text-field v-model="name" type="text" label="name"></v-text-field>
              <v-text-field v-model="details" type="text" label="detail"></v-text-field>
              <v-text-field v-model="start" type="date" label="start"></v-text-field>
              <v-text-field v-model="end" type="date" label="end"></v-text-field>
              <v-text-field v-model="color" label="color"></v-text-field>
              <v-btn type="submit" color="success" class="mr-4" @click.stop="dialog = false">
                submit
              </v-btn>
            </v-form>
          </v-container>
        </v-card>
      </v-dialog>

      <v-sheet height="600">
        <v-calendar
          ref="calendar"
          v-model="focus"
          color="primary"
          :events="events"
          :event-color="getEventColor"
          :event-margin-bottom="3"
          :now="today"
          :type="type"
          @click:event="showEvent"
          @click:more="viewDay"
          @click:date="viewDay"
          @change="updateRange"
        ></v-calendar>
        <v-menu
          v-model="selectedOpen"
          :close-on-content-click="false"
          :activator="selectedElement"
          full-width
          offset-x
        >
          <v-card
            color="grey lighten-4"
            min-width="350px"
            flat
          >
            <v-toolbar
              :color="selectedEvent.color"
              dark
            >
              <v-btn icon>
                <v-icon>mdi-pencil</v-icon>
              </v-btn>
              <v-toolbar-title v-html="selectedEvent.name"></v-toolbar-title>
              <div class="flex-grow-1"></div>
              <v-btn icon>
                <v-icon>mdi-heart</v-icon>
              </v-btn>
              <v-btn icon>
                <v-icon>mdi-dots-vertical</v-icon>
              </v-btn>
            </v-toolbar>
            <v-card-text>
              <span v-html="selectedEvent.details"></span>
            </v-card-text>
            <v-card-actions>
              <v-btn
                text
                color="secondary"
                @click="selectedOpen = false"
              >
                Cancel
              </v-btn>
            </v-card-actions>
          </v-card>
        </v-menu>
      </v-sheet>
    </v-col>
  </v-row>
</template>

<script>
  //import moment from 'moment'
  export default {
    data: () => ({
      today: '2019-01-08',
      focus: '2019-01-08',
      type: 'month',
      typeToLabel: {
        month: 'Month',
        week: 'Week',
        day: 'Day',
        '4day': '4 Days',
      },
      name: null,
      details: null,
      start: null,
      end: null,
      color: null,
      selectedEvent: {},
      selectedElement: null,
      selectedOpen: false,
      events: [
        {
          name: 'Vacation',
          details: 'Going to the beach!',
          start: '2018-12-29',
          end: '2019-01-01',
          color: 'blue',
        }
      ],
      dialog: false,
    }),
    computed: {
      title () {
        const { start, end } = this
        if (!start || !end) {
          return ''
        }
        const startMonth = this.monthFormatter(start)
        const endMonth = this.monthFormatter(end)
        const suffixMonth = startMonth === endMonth ? '' : endMonth
        const startYear = start.year
        const endYear = end.year
        const suffixYear = startYear === endYear ? '' : endYear
        const startDay = start.day + this.nth(start.day)
        const endDay = end.day + this.nth(end.day)
        switch (this.type) {
          case 'month':
            return `${startMonth} ${startYear}`
          case 'week':
          case '4day':
            return `${startMonth} ${startDay} ${startYear} - ${suffixMonth} ${endDay} ${suffixYear}`
          case 'day':
            return `${startMonth} ${startDay} ${startYear}`
        }
        return ''
      },
      monthFormatter () {
        return this.$refs.calendar.getFormatter({
          timeZone: 'UTC', month: 'long',
        })
      },
    },
    methods: {
      viewDay ({ date }) {
        this.focus = date
        this.type = 'day'
      },
      getEventColor (event) {
        return event.color
      },
      setToday () {
        this.focus = this.today
      },
      prev () {
        this.$refs.calendar.prev()
      },
      next () {
        this.$refs.calendar.next()
      },
      async addEvent () {
        this.start = await new Date(this.start).toISOString().substring(0,10)
        this.end =  await new Date(this.end).toISOString().substring(0,10)
        console.log(this.start)
        this.events.push({name: this.name})
        this.events.push({details: this.details})
        this.events.push({start: this.start})
        this.events.push({end: this.end})
        this.events.push({color: this.color})
      },
      showEvent ({ nativeEvent, event }) {
        const open = () => {
          this.selectedEvent = event
          this.selectedElement = nativeEvent.target
          setTimeout(() => this.selectedOpen = true, 10)
        }
        if (this.selectedOpen) {
          this.selectedOpen = false
          setTimeout(open, 10)
        } else {
          open()
        }
        nativeEvent.stopPropagation()
      },
      updateRange ({ start, end }) {
        // You could load events from an outside source (like database) now that we have the start and end dates on the calendar
        this.start = start
        this.end = end
      },
      nth (d) {
        return d > 3 && d < 21
          ? 'th'
          : ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'][d % 10]
      },
    },
  }
</script>


like image 244
JS_is_awesome18 Avatar asked Aug 29 '19 21:08

JS_is_awesome18


3 Answers

As the developer of the Vuetify calendar, here's my two cents. The reason why events take a string is to distinguish between an all-day event and an event that is timed. An all-day event is in the format of YYYY-MM-DD and a timed event has the date format YYYY-MM-DD HH:mm:ss (where seconds is optional, and numbers don't need to be zero padded.)

Having said that, when this PR is merged in and released you will be able to pass dates or UTC timestamps:

https://github.com/vuetifyjs/vuetify/pull/11198

You can then define a function or property on the event that marks it as a timed event.

like image 56
ClickerMonkey Avatar answered Oct 20 '22 23:10

ClickerMonkey


No need to moment.js which will be used only for 2 lines of code, so you could do it simply like :

   addEvent () {
        this.start = new Date(this.start).toISOString().substring(0,10);
        this.end =  new Date(this.end).toISOString().substring(0,10);
        ...
            this.events.push({name: this.name,
                              details: this.details,
                              start: this.start,
                              end: this.end,
                             color: this.color})
See the Pen Vuetify Example Pen by boussadjra (@boussadjra) on CodePen.
like image 8
Boussadjra Brahim Avatar answered Oct 20 '22 23:10

Boussadjra Brahim


I would advice to format your date to MM-DD-YYYY instead of modifying vuetify, then convert it to whatever format you need when you submit the form.

Moment.js is an awesome library for this type of conversions and has an easy API.

In your case, you could simply do this.end = moment(this.end).format('MM-DD-YYYY');

like image 2
Sølve Tornøe Avatar answered Oct 20 '22 23:10

Sølve Tornøe