Overview

  • Vue.js appointment calendar created using DayPilot JavaScript calendar component

  • How to create and configure the Vue.js calendar

  • How to load event/appointment data

  • How to add support for creating new appointment using drag and drop

  • This project was generated using Calendar UI Builder

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

Vue.js Calendar Component

vue-js-appointment-calendar-component-initialization.png

Let's start with a blank Vue.js project. We will create a new Vue.js component that displays an appointment calendar using DayPilot Vue.js Calendar.

The Vue.js Calendar component is included in the Vue.js package of DayPilot Pro for JavaScript. You can install it using a link from npm.daypilot.org:

yarn add https://npm.daypilot.org/daypilot-pro-vue/trial/2020.4.4807.tar.gz

First, we create a new Calendar component using <DayPilotCalendar> tag. Our calendar component will define the calendar appearance and behavior:

components/Calendar.vue

<template>
  <DayPilotCalendar id="dp" />
</template>

<script>
import {DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  components: {
    DayPilotCalendar
  },
}
</script>

Now we can add the calendar to our Vue application:

App.vue

<template>
  <div id="app">
    <Calendar />
  </div>
</template>

<script>
import Calendar from './components/Calendar.vue'

export default {
  name: 'app',
  components: {
    Calendar
  }
}
</script>

Vue.js Weekly Calendar Configuration

vue.js-weekly-calendar-component.png

By default, the calendar display a day view. We want to switch it to a week view and this can be done by setting the viewType property to "Week"

The calendar properties can be specified using the :config attribute of the component. We have set the value to "config" which tells the calendar to look for config object in the application data.

<template>
  <DayPilotCalendar id="dp" :config="config" />
</template>

<script>
import {DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
      },
    }
  },
  components: {
    DayPilotCalendar
  },
}
</script>

You can use the config object to set additional calendar properties and event handlers. Changes made to the config object using Vue.set() method will be detected by Vue and the Calendar component will be updated automatically.

Loading Appointments

vue.js-weekly-calendar-component-loading-events.png

In order to load events we need to access the calendar object (DayPilot.Calendar class) and use its API. This object is saved as control property of the Vue.js component.

To make it easily accessible, we will add a calendar computed property to our Vue.js application. It finds the calendar Vue.js component using ref attribute and returns the DayPilot.Calendar object.

<template>
  <DayPilotCalendar id="dp" :config="config" ref="calendar" />
</template>

<script>
import {DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
      },
    }
  },
  components: {
    DayPilotCalendar
  },
  computed: {
    calendar() {
      return this.$refs.calendar.control;
    }
  },

}
</script>

The appointment data can be displayed using update() method. The update() methods accepts an object with calendar properties to be updated. It loads the properties and redraws the calendar UI.

<template>
  <DayPilotCalendar id="dp" :config="config" ref="calendar" />
</template>

<script>
import {DayPilot, DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
      },
    }
  },
  props: {
  },
  components: {
    DayPilotCalendar
  },
  computed: {
    calendar() {
      return this.$refs.calendar.control;
    }
  },
  methods: {
    loadEvents() {
      // placeholder for an AJAX call
      var data = [
        {
          id: 1,
          start: DayPilot.Date.today().addHours(10),
          end: DayPilot.Date.today().addHours(11),
          text: "Event 1"
        },
        {
          id: 2,
          start: DayPilot.Date.today().addHours(13),
          end: DayPilot.Date.today().addHours(16),
          text: "Event 2"
        }
      ];
      this.calendar.update({events: data});
    },
  },
  mounted() {
    this.loadEvents();
  }
}
</script>

Creating New Appointments

vue.js-weekly-calendar-component-create-event.png

The JavaScript calendar lets users users create new appointments using drag and drop time range selection.

To handle the user action, we'll add onTimeRangeSelected event handler to the config object.

<script>
import {DayPilot, DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
        onTimeRangeSelected: (args) => {
          DayPilot.Modal.prompt("Create a new event:", "Event 1").then((modal) => {
            var dp = args.control;
            dp.clearSelection();
            if (modal.canceled) {
              return;
            }
            dp.events.add({
              start: args.start,
              end: args.end,
              id: DayPilot.guid(),
              text: modal.result
            });
          });
        },
      },
    }
  },
 
  // ...

}
</script>

Calendar Appointment Context Menu

vue.js-weekly-calendar-component-context-menu.png

In order to allow additional actions to be performed we will add a context menu to the calendar appointments. It will let users delete the appointment or change the highlight color.

First, we need to define the context menu. It will display a “Delete” command, a separator, and four items that will allow color changes:

<script>
import {DayPilot, DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
        contextMenu: new DayPilot.Menu({
          items: [
            {
              text: "Delete",
              onClick: (args) => {
                var e = args.source;
                this.calendar.events.remove(e);
                this.calendar.message("Deleted.");
              }
            },
            {
              text: "-"
            }, {
              text: "Blue",
              icon: "icon icon-blue",
              color: "#1155cc",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },
            {
              text: "Green",
              icon: "icon icon-green",
              color: "#6aa84f",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },
            {
              text: "Yellow",
              icon: "icon icon-yellow",
              color: "#f1c232",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },
            {
              text: "Red",
              icon: "icon icon-red",
              color: "#cc0000",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },

          ]
        })
      },
    }
  },

  // ...

}
</script>

The menu defined using contextMenu property will be linked to appointments. Our users can activate it by right-clicking the appointment.

However, it's not obvious that the context menu is available so we'll add a visual hint that will appear when the users hover over an appointment. We can add this hint using an active area - a custom object with predefined location and appearance that will appear on hover. We will add the active area using onBeforeEventRender event handler:

<template>
  <DayPilotCalendar id="dp" :config="config" ref="calendar" />
</template>

<script>
import {DayPilot, DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
        onBeforeEventRender: (args) => {
          args.data.barColor = args.data.color;
          args.data.areas = [
            {
              top: 6,
              right: 2,
              icon: "icon-triangle-down",
              visibility: "Hover",
              action: "ContextMenu",
              style: "font-size: 12px; background-color: #f9f9f9; border: 1px solid #ccc; padding: 2px 2px 0px 2px; cursor:pointer;"
            }
          ];
        },
      },
    }
  },

  // ...

}
</script>

Complete Source Code of the Vue.js Calendar Component

components/Calendar.vue

<template>
  <DayPilotCalendar id="dp" :config="config" ref="calendar" />
</template>

<script>
import {DayPilot, DayPilotCalendar} from 'daypilot-pro-vue'

export default {
  name: 'Calendar',
  data: function() {
    return {
      config: {
        viewType: "Week",
        timeRangeSelectedHandling: "Enabled",
        onTimeRangeSelected: (args) => {
          DayPilot.Modal.prompt("Create a new event:", "Event 1").then((modal) => {
            var dp = args.control;
            dp.clearSelection();
            if (modal.canceled) {
              return;
            }
            dp.events.add({
              start: args.start,
              end: args.end,
              id: DayPilot.guid(),
              text: modal.result
            });
          });
        },
        eventDeleteHandling: "Disabled",
        onEventMoved: () => {
          this.message("Event moved");
        },
        onEventResized: () => {
          this.message("Event resized");
        },
        onBeforeEventRender: (args) => {
          args.data.barColor = args.data.color;
          args.data.areas = [
            {
              top: 6,
              right: 2,
              icon: "icon-triangle-down",
              visibility: "Hover",
              action: "ContextMenu",
              style: "font-size: 12px; background-color: #f9f9f9; border: 1px solid #ccc; padding: 2px 2px 0px 2px; cursor:pointer;"
            }
          ];
        },
        contextMenu: new DayPilot.Menu({
          items: [
            {
              text: "Delete",
              onClick: (args) => {
                var e = args.source;
                this.calendar.events.remove(e);
                this.calendar.message("Deleted.");
              }
            },
            {
              text: "-"
            }, {
              text: "Blue",
              icon: "icon icon-blue",
              color: "#1155cc",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },
            {
              text: "Green",
              icon: "icon icon-green",
              color: "#6aa84f",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },
            {
              text: "Yellow",
              icon: "icon icon-yellow",
              color: "#f1c232",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },
            {
              text: "Red",
              icon: "icon icon-red",
              color: "#cc0000",
              onClick: (args) => {
                this.updateColor(args.source, args.item.color);
              }
            },

          ]
        })
      },
    }
  },
  props: {
  },
  components: {
    DayPilotCalendar
  },
  computed: {
    // DayPilot.Calendar object - https://api.daypilot.org/daypilot-calendar-class/
    calendar() {
      return this.$refs.calendar.control;
    }
  },
  methods: {
    loadEvents() {
      // placeholder for an AJAX call
      var data = [
        {
          id: 1,
          start: DayPilot.Date.today().addHours(10),
          end: DayPilot.Date.today().addHours(11),
          text: "Event 1"
        },
        {
          id: 2,
          start: DayPilot.Date.today().addHours(13),
          end: DayPilot.Date.today().addHours(16),
          text: "Event 2"
        }
      ];
      this.calendar.update({events: data});
    },
    updateColor(e, color) {
      var dp = this.calendar;
      e.data.color = color;
      dp.events.update(e);
      dp.message("Color updated");
    }
  },
  mounted() {
    this.loadEvents();
    this.calendar.message("Welcome!");
  }
}
</script>

History

  • December 16, 2020: Upgraded to DayPilot Pro for JavaScript 2020.4.4807. Using NPM package (daypilot-pro-vue).

  • September 18, 2019: Upgraded to DayPilot Pro for JavaScript 2019.3.4012. Context menu added.

  • April 11, 2018: Initial release