Features

  • Vue.js scheduler component created using DayPilot JavaScript Scheduler
  • The scheduler component displays a hierarchy of resources on the vertical axis
  • The timeline is displayed on the horizontal axis
  • The appearance and behavior can be customized easily
  • Full drag and drop support
  • The Vue.js project was generated using Scheduler UI Builder
  • Complete Vue.js application is available for download
  • Includes a trial version of DayPilot Pro for JavaScript (see License below)

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.

TLDR: Skip This Tutorial and Generate a Customized Vue.js Project

vuejs-scheduler-project-configurator.png

You can use the online Scheduler UI Builder application to create a customized Scheduler configuration using a visual configurator tool with live preview. Generate and download a complete Vue.js project with all dependencies.

JavaScript Dependencies

First, include the JavaScript dependencies (Vue.js and DayPilot Pro). The order is not important.

<!-- DayPilot library -->
<script src="js/daypilot/daypilot-all.min.js"></script>

<!-- Vue.js -->
<script src="https://unpkg.com/vue"></script>

Vue.js Application

The initial Vue.js application is very simple. We initialize the application by creating a new Vue() object, referencing "#scheduler-app" as the target element:

HTML

<div id="scheduler-app">
  <h1>Vue.js Scheduler Application</h1>
</div>

JavaScript

new Vue({
  el: '#scheduler-app',
  data: { }
});

Vue.js Scheduler Component

In this step, we will create a new scheduler Vue.js component. Our component will use DayPilot.Scheduler to render the scheduler UI in the browser.

The component template contains an empty div that will server as the placeholder for the Scheduler. The Scheduler needs a target div that will be used to display the content. The Scheduler itself will be rendered automatically during initialization (see the mounted() function).

Our component will be accessible using <scheduler> tag. It has two properties (props):

  • The id attribute (required) specifies the Scheduler id. This id will be used for the Scheduler DOM element.
  • The config attribute specifies a JavaScript object with the initial Scheduler configuration.
Vue.component('scheduler', {
  props: ['id', 'config'],
  template: '<div :id="id"></div>',
  mounted: function() { this.control = new DayPilot.Scheduler(this.id, this.config).init(); }
});

Initial Vue.js Scheduler Configuration

vue-js-scheduler-reservation-application-initial-configuration.png

Now we can add the empty Scheduler to our Vue.js application. We will replace the <h1> element with the new <scheduler> component:

HTML

<div id="scheduler-app">
  <scheduler id="dp" :config="initConfig" ref="scheduler"></scheduler>
</div>

We will use "dp" as the Scheduler id. We also specify the initial configuration object using :config attribute. It points to "initConfig" object that is defined in the Vue.js "data" section. This object will let us set the Scheduler properties and event handlers. This first version specifies only the basic properties that define the Scheduler timeline (timeHeader, scale, days, startDate).

JavaScript

new Vue({
  el: '#scheduler-app',
  data: {
    initConfig: {
      timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}],
      scale: "Day",
      days: DayPilot.Date.today().daysInMonth(),
      startDate: DayPilot.Date.today().firstDayOfMonth()
    }
  }
});

Accessing the Scheduler Object in Vue.js

The Scheduler component uses DayPilot.Scheduler internally to create the component. We need a reference to the DayPilot.Scheduler object in order to call its methods using the JavaScript API.

First, we need a reference to the Vue.js scheduler object. We can get it by adding the ref attribute to the <scheduler> element:

<scheduler id="dp" :config="initConfig" ref="scheduler"></scheduler>

Now we can reach the Vue.js component using $refs:

var component = this.$refs.scheduler;

The Vue.js component stores the internal DayPilot.Scheduler instance using "control" property. To make the access easier, we will add a new computed property to our Vue.js application:

computed: {
  scheduler: function() { return this.$refs.scheduler.control; }
},

Loading Vue.js Scheduler Resources

vue-js-scheduler-reservation-application-resources.png

We will create loadResources() events that loads the resource data and updates the Scheduler:

methods: {
  loadResources: function() {
    // placeholder for an AJAX call
    var data = [
      { name: "Group A", id: "GA", expanded: true, children: [
        {name: "Resource 1", id: "R1"},
        {name: "Resource 2", id: "R2"},
        {name: "Resource 3", id: "R3"},
        {name: "Resource 4", id: "R4"},
      ]},
      { name: "Group B", id: "GB", expanded: true, children: [
        {name: "Resource 5", id: "R5"},
        {name: "Resource 6", id: "R6"},
        {name: "Resource 7", id: "R7"},
        {name: "Resource 8", id: "R8"},
      ]}
    ];
    this.scheduler.update({resources: data});
  },
  // ...
}

Loading Vue.js Scheduler Reservations

vue-js-scheduler-reservation-application-loading-reservations.png

We will create loadEvents() method that loads the event data to the Scheduler using update() call. Normally, this method should load the data from the server side using an HTTP call but we will return a static array in this example:

methods: {
  loadEvents: function() {
    // placeholder for an AJAX call
    var data = [
      {
        id: 1,
        resource: "R1",
        start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
        end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
        text: "Event 1"
      },
      {
        id: 2,
        resource: "R1",
        start: DayPilot.Date.today().firstDayOfMonth().addDays(10),
        end: DayPilot.Date.today().firstDayOfMonth().addDays(13),
        text: "Event 2"
      }
    ];
    this.scheduler.update({events: data});
  },
  // ...
},

Loading the Data during App Initialization

Now we need to add the loading methods to the mounted event so they will be called during the Vue.js app initialization:

mounted: function() {
  this.loadResources();
  this.loadEvents();
}

Reservation Context Menu

vue-js-scheduler-reservation-application-context-menu.png

In this step, we will add a context menu to the reservations. The context menu will let users change the reservation color and delete it.

The context menu can be defined using contextMenu config property. Users can activate the context menu by right-clicking the reservation.

We will also add an icon to the reservation upper-left corner that will serve as a hint that a context menu is available. The icon can be added by inserting an active area using onBeforeEventRender event handler.

onBeforeEventRender: function(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: function(args) {
                var e = args.source;
                app.scheduler.events.remove(e);
                app.scheduler.message("Deleted.");
            }
        },
        {
            text: "-"
        },                        {
            text: "Blue",
            icon: "icon icon-blue",
            color: "#1155cc",
            onClick: function(args) { app.updateColor(args.source, args.item.color); }
        },
        {
            text: "Green",
            icon: "icon icon-green",
            color: "#6aa84f",
            onClick: function(args) { app.updateColor(args.source, args.item.color); }
        },
        {
            text: "Yellow",
            icon: "icon icon-yellow",
            color: "#f1c232",
            onClick: function(args) { app.updateColor(args.source, args.item.color); }
        },
        {
            text: "Red",
            icon: "icon icon-red",
            color: "#cc0000",
            onClick: function(args) { app.updateColor(args.source, args.item.color); }
        },

    ]
})

The updateColor() method is defined in the Vue.js app object ("methods" section). It changes the reservation data object properties ("color") and calls the Scheduler API to update the UI.

var app = new Vue({
  el: '#scheduler-app',
  methods: {
      // ...
      updateColor: function(e, color) {
          var dp = this.scheduler;
          e.data.color = color;
          dp.events.update(e);
          dp.message("Color updated");
      }
  },
  // ...
});

Complete Vue.js App Source Code

Here you can find the full source code of our Vue.js application. 

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <title>Vue.js Scheduler: Build a Reservation Application in 5 Minutes</title>

    <link href="index.css" rel="stylesheet" type="text/css">
    <link href="icons/style.css" rel="stylesheet" type="text/css">

    <!-- DayPilot library -->
    <script src="js/daypilot/daypilot-all.min.js"></script>

    <!-- Vue.js -->
    <script src="https://unpkg.com/vue"></script>

</head>
<body>
<div class="header">
    <h1><a href='https://code.daypilot.org/69423/vue-js-scheduler-build-a-reservation-application-in-5-minut'>Vue.js Scheduler: Build a Reservation Application in 5 Minutes</a></h1>
    <div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - AJAX Calendar/Scheduling Widgets for JavaScript/HTML5/jQuery/AngularJS
    </div>
</div>

<div class="main">

    <div id="scheduler-app">
        <scheduler id="dp" :config="initConfig" ref="scheduler"></scheduler>
    </div>

</div>

<script>
    Vue.component('scheduler', {
        props: ['id', 'config'],
        template: '<div :id="id"></div>',
        mounted: function () {
            this.control = new DayPilot.Scheduler(this.id, this.config).init();
        }
    });

    var app = new Vue({
        el: '#scheduler-app',
        data: {
            initConfig: {
                timeHeaders: [{"groupBy": "Month"}, {"groupBy": "Day", "format": "d"}],
                scale: "Day",
                days: DayPilot.Date.today().daysInMonth(),
                startDate: DayPilot.Date.today().firstDayOfMonth(),
                timeRangeSelectedHandling: "Enabled",
                eventHeight: 40,
                onTimeRangeSelected: function (args) {
                    var dp = this;
                    DayPilot.Modal.prompt("Create a new event:", "Event 1").then(function (modal) {
                        dp.clearSelection();
                        if (!modal.result) {
                            return;
                        }
                        dp.events.add(new DayPilot.Event({
                            start: args.start,
                            end: args.end,
                            id: DayPilot.guid(),
                            resource: args.resource,
                            text: modal.result
                        }));
                    });
                },
                eventMoveHandling: "Update",
                onEventMoved: function (args) {
                    this.message("Event moved");
                },
                eventResizeHandling: "Update",
                onEventResized: function (args) {
                    this.message("Event resized");
                },
                eventClickHandling: "Enabled",
                onEventClicked: function (args) {
                    this.message("Event clicked");
                },
                eventHoverHandling: "Disabled",
                treeEnabled: true,
                onBeforeEventRender: function(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: function(args) {
                                var e = args.source;
                                app.scheduler.events.remove(e);
                                app.scheduler.message("Deleted.");
                            }
                        },
                        {
                            text: "-"
                        },                        {
                            text: "Blue",
                            icon: "icon icon-blue",
                            color: "#1155cc",
                            onClick: function(args) { app.updateColor(args.source, args.item.color); }
                        },
                        {
                            text: "Green",
                            icon: "icon icon-green",
                            color: "#6aa84f",
                            onClick: function(args) { app.updateColor(args.source, args.item.color); }
                        },
                        {
                            text: "Yellow",
                            icon: "icon icon-yellow",
                            color: "#f1c232",
                            onClick: function(args) { app.updateColor(args.source, args.item.color); }
                        },
                        {
                            text: "Red",
                            icon: "icon icon-red",
                            color: "#cc0000",
                            onClick: function(args) { app.updateColor(args.source, args.item.color); }
                        },

                    ]
                })
            }
        },
        computed: {
            // DayPilot.Scheduler object
            // https://api.daypilot.org/daypilot-scheduler-class/
            scheduler: function () {
                return this.$refs.scheduler.control;
            }
        },
        methods: {
            loadReservations: function () {
                // placeholder for an AJAX call
                var data = [
                    {
                        id: 1,
                        resource: "R1",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
                        text: "Event 1",
                        color: "#1155cc"
                    },
                    {
                        id: 2,
                        resource: "R1",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(9),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(12),
                        text: "Event 2",
                        color: "#6aa84f"
                    },
                    {
                        id: 3,
                        resource: "R3",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(5),
                        text: "Event 3",
                        color: "#1155cc"
                    },
                    {
                        id: 4,
                        resource: "R3",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(5),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
                        text: "Event 4",
                        color: "#6aa84f"
                    },
                    {
                        id: 5,
                        resource: "R3",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(7),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(9),
                        text: "Event 5",
                        color: "#f1c232"
                    },
                    {
                        id: 6,
                        resource: "R3",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(9),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(11),
                        text: "Event 6",
                        color: "#cc0000"
                    },
                ];
                this.scheduler.update({events: data});
            },
            loadResources: function () {
                // placeholder for an AJAX call
                var data = [
                    {
                        name: "Group A", id: "GA", expanded: true, children: [
                        {name: "Resource 1", id: "R1"},
                        {name: "Resource 2", id: "R2"},
                        {name: "Resource 3", id: "R3"},
                        {name: "Resource 4", id: "R4"},
                    ]
                    },
                    {
                        name: "Group B", id: "GB", expanded: true, children: [
                        {name: "Resource 5", id: "R5"},
                        {name: "Resource 6", id: "R6"},
                        {name: "Resource 7", id: "R7"},
                        {name: "Resource 8", id: "R8"},
                    ]
                    }
                ];
                this.scheduler.update({resources: data});
            },
            updateColor: function(e, color) {
                var dp = this.scheduler;
                e.data.color = color;
                dp.events.update(e);
                dp.message("Color updated");
            }
        },
        mounted: function () {
            this.loadResources();
            this.loadReservations();
        }
    });

</script>
</body>
</html>

History

  • September 24, 2019: Upgraded to DayPilot Pro for JavaScript 2019.3.4012
  • February 9, 2018: Context menu added
  • February 5, 2018: Initial release