Features

  • Vue.js scheduler component created using DayPilot JavaScript Scheduler
  • Displays a hierarchy of resources on the vertical axis
  • Timeline on horizontal axis
  • Customizable appearance and behavior
  • Drag and drop support
  • Project generated using Scheduler UI Builder
  • Complete Vue.js application 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 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):

<!-- 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

We need to create a simple Vue.js component that uses DayPilot.Scheduler to render the scheduler UI in the browser.

The component will be accessible as <scheduler> and it has two properties:

  • 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

vuejs-scheduler-initial-configuration.png

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

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 we need to add to the Vue.js "data" section. This object will let us set the Scheduler properties and event handlers.

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

vuejs-scheduler-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: "Group B", id: "GB", expanded: true, children: [
        { name: "Resource 3", id: "R3"},
        { name: "Resource 4", id: "R4"}
      ]}
    ];
    this.scheduler.update({resources: data});
  },
  // ...
}

Loading Vue.js Scheduler Reservations

vuejs-scheduler-reservations.png

We will create loadEvents() method that will load the event data to the Scheduler using update() call:

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(5),
        end: DayPilot.Date.today().firstDayOfMonth().addDays(10),
        text: "Event 2"
      }
    ];
    this.scheduler.update({events: data});
  },
  // ...
},

Loading the Data during App Initialization

We will call the loading methods during the Vue.js app initialization:

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

Reservation Context Menu

vuejs-scheduler-reservation-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

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <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",
                        barColor: "#cc0000"
                    },
                    {
                        id: 2,
                        resource: "R2",
                        start: DayPilot.Date.today().firstDayOfMonth().addDays(5),
                        end: DayPilot.Date.today().firstDayOfMonth().addDays(10),
                        text: "Event 2",
                        barColor: "#38761d"
                    }
                ];
                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: "Group B", id: "GB", expanded: true, children: [
                        {name: "Resource 3", id: "R3"},
                        {name: "Resource 4", id: "R4"}
                    ]
                    }
                ];
                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>