Features
Vue 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
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.
TLDR: Skip This Tutorial and Generate a Customized Vue.js Project
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 2 or Vue 3 project with all dependencies.
NPM Dependencies
First, add daypilot-pro-vue
package from npm.daypilot.org to your Vue application:
npm install https://npm.daypilot.org/daypilot-pro-vue/trial/2024.4.6180.tar.gz
Vue Application
The first version of our Vue scheduler application is very simple. We display the Scheduler
Vue component that we will create in the next step:
App.vue
<template>
<Scheduler />
</template>
<script setup>
import Scheduler from './components/Scheduler.vue'
</script>
Vue Scheduler Component
In this step, we will create a new Vue Scheduler component. Our component will use DayPilotScheduler
from daypilot-pro-vue
package to render the scheduler UI in the browser.
Template:
<template>
<DayPilotScheduler :config="config" ref="schedulerRef" />
</template>
JavaScript:
<script setup>
import {DayPilot, DayPilotScheduler} from 'daypilot-pro-vue'
const config = reactive({});
const schedulerRef = ref(null);
</script>
The component template contains a <DayPilotScheduler>
tag with two attributes:
The
config
attribute specifies a JavaScript object with the initial Scheduler configuration.The
ref
attribute lets us access the direct API using theDayPilot.Scheduler
object.
Initial Vue.js Scheduler Configuration
We have added an empty Scheduler to our Vue.js application. It uses the default configuration and the view doesn’t display much. In this step, we will use the config
property to customize the Scheduler appearance.
You can use the config object to set the Scheduler properties and event handlers. This first version specifies only basic properties that define the Scheduler timeline (timeHeader
, scale
, days
, startDate
).
JavaScript
<script setup>
import {DayPilot, DayPilotScheduler} from 'daypilot-pro-vue'
const config = reactive({
timeHeaders: [{groupBy: "Month"}, {groupBy: "Day", format: "d"}],
scale: "Day",
days: DayPilot.Date.today().daysInYear(),
startDate: DayPilot.Date.today().firstDayOfYear(),
});
const schedulerRef = ref(null);
</script>
Accessing the Scheduler Object in Vue
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 using the ref
attribute of the <DayPilotScheduler>
element:
<DayPilotScheduler :config="config" ref="schedulerRef" />
Now we can reach the Vue.js component using schedulerRef
:
const component = schedulerRef.value;
The DayPilotScheduler
Vue.js component stores the internal DayPilot.Scheduler
instance in the control
property.
const scheduler = schedulerRef.value?.control;
Now we can use the dp
constant to reach the DayPilot.Scheduler
object:
onMounted(() => {
const scheduler = schedulerRef.value?.control;
scheduler.message("Welcome!");
scheduler.scrollTo(DayPilot.Date.today().firstDayOfMonth());
});
Loading Vue.js Scheduler Resources
In this step, we will create a loadResources()
function that loads the resource data and updates the Scheduler:
const loadResources = () => {
const resources = [
{
name: "Group A", id: "GA", expanded: true, children: [
{name: "Resource 1", id: "R1", location: "Location 1"},
{name: "Resource 2", id: "R2", location: "Location 1"},
{name: "Resource 3", id: "R3", location: "Location 2"},
{name: "Resource 4", id: "R4", location: "Location 2", status: "locked"},
]
},
{
name: "Group B", id: "GB", expanded: true, children: [
{name: "Resource 5", id: "R5", location: "Location 3"},
{name: "Resource 6", id: "R6", location: "Location 3"},
{name: "Resource 7", id: "R7", location: "Location 4"},
{name: "Resource 8", id: "R8", location: "Location 4"},
]
}
];
config.resources = resources;
};
Loading Vue.js Scheduler Reservations
Now we will create loadReservations()
function that loads the event data to the Scheduler. 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:
const loadReservations = () => {
const events = [
{
id: 1,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
text: "Event 1",
color: "#6fa8dc"
},
{
id: 2,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(9),
end: DayPilot.Date.today().firstDayOfMonth().addDays(12),
text: "Event 2",
color: "#93c47d"
},
// ...
];
config.events = events;
};
You can also load the events using the direct API. The direct API is optimized to only perform partial updates when possible.
Instead of using the config
object to update the data:
config.events = events;
we will use the update() method:
schedulerRef.value?.control.update({events});
Loading the Data during App Initialization
Now we need to add the loading methods to the onMounted
lifecycle hook so they will be called during the Vue.js app initialization:
onMounted(() => {
const scheduler = schedulerRef.value?.control;
loadResources();
loadReservations();
scheduler.message("Welcome!");
scheduler.scrollTo(DayPilot.Date.today().firstDayOfMonth());
});
Reservation Context Menu
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 the contextMenu config property. Users can activate the context menu by right-clicking the reservation.
We will also add an icon to the right side of the reservation box 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.
const config = reactive({
// ...
onBeforeEventRender: args => {
args.data.backColor = args.data.color;
args.data.borderColor = "darker";
args.data.fontColor = "#ffffff";
args.data.areas = [
{
top: 10,
right: 6,
width: 20,
height: 20,
symbol: "icons/daypilot.svg#minichevron-down-4",
fontColor: "#999999",
backColor: "#f9f9f9",
borderRadius: "50%",
visibility: "Visible",
action: "ContextMenu",
padding: 1,
style: "border: 2px solid #ccc; cursor:pointer;"
}
];
},
contextMenu: new DayPilot.Menu({
items: [
{
text: "Delete",
onClick: args => {
const e = args.source;
const scheduler = schedulerRef.value?.control;
scheduler.events.remove(e);
scheduler.message("Deleted.");
}
},
{
text: "-"
},
{
text: "Blue",
icon: "icon icon-blue",
color: "#6fa8dc",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
{
text: "Green",
icon: "icon icon-green",
color: "#93c47d",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
{
text: "Yellow",
icon: "icon icon-yellow",
color: "#f1c232",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
{
text: "Red",
icon: "icon icon-red",
color: "#dd7e6b",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
]
})
});
The updateColor()
function changes the color
property of the reservation data object and calls the Scheduler API to update the UI.
const updateColor = (e, color) => {
const scheduler = schedulerRef.value?.control;
e.data.color = color;
scheduler.events.update(e);
scheduler.message("Color updated");
};
Complete Vue App Source Code
Here you can find the full source code of our Vue.js application.
Scheduler.vue
<template>
<DayPilotScheduler :config="config" ref="schedulerRef" />
</template>
<script setup>
import { DayPilot, DayPilotScheduler } from 'daypilot-pro-vue';
import { ref, reactive, onMounted } from 'vue';
const config = reactive({
timeHeaders: [{groupBy: "Month"}, {groupBy: "Day", format: "d"}],
scale: "Day",
days: DayPilot.Date.today().daysInYear(),
startDate: DayPilot.Date.today().firstDayOfYear(),
timeRangeSelectedHandling: "Enabled",
eventHeight: 40,
durationBarVisible: false,
eventBorderRadius: 20,
rowMarginTop: 2,
rowMarginBottom: 2,
rowHeaderColumns: [
{title: "Name", display: "name"},
{title: "Location", display: "location"},
{title: "Status", width: 50}
],
onTimeRangeSelected: async args => {
const scheduler = schedulerRef.value?.control;
const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
scheduler.clearSelection();
if (modal.canceled) {
return;
}
scheduler.events.add({
start: args.start,
end: args.end,
id: DayPilot.guid(),
resource: args.resource,
text: modal.result
});
},
eventMoveHandling: "Update",
onEventMoved: args => {
args.control.message("Event moved: " + args.e.data.text);
},
eventResizeHandling: "Update",
onEventResized: args => {
args.control.message("Event resized: " + args.e.data.text);
},
eventClickHandling: "Enabled",
onEventClicked: args => {
args.control.message("Event clicked: " + args.e.data.text);
},
eventHoverHandling: "Disabled",
treeEnabled: true,
onBeforeRowHeaderRender: args => {
if (args.row.data.status === "locked") {
args.row.columns[2].areas = [
{
top: "calc(50% - 10px)",
left: "calc(50% - 10px)",
width: 20,
height: 20,
symbol: "icons/daypilot.svg#padlock",
fontColor: "#999999",
visibility: "Visible",
}
];
}
},
onBeforeEventRender: args => {
args.data.backColor = args.data.color;
args.data.borderColor = "darker";
args.data.fontColor = "#ffffff";
args.data.areas = [
{
top: 10,
right: 6,
width: 20,
height: 20,
symbol: "icons/daypilot.svg#minichevron-down-4",
fontColor: "#999999",
backColor: "#f9f9f9",
borderRadius: "50%",
visibility: "Visible",
action: "ContextMenu",
padding: 1,
style: "border: 2px solid #ccc; cursor:pointer;"
}
];
},
contextMenu: new DayPilot.Menu({
items: [
{
text: "Delete",
onClick: args => {
const e = args.source;
const scheduler = schedulerRef.value?.control;
scheduler.events.remove(e);
scheduler.message("Deleted.");
}
},
{
text: "-"
},
{
text: "Blue",
icon: "icon icon-blue",
color: "#6fa8dc",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
{
text: "Green",
icon: "icon icon-green",
color: "#93c47d",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
{
text: "Yellow",
icon: "icon icon-yellow",
color: "#f1c232",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
{
text: "Red",
icon: "icon icon-red",
color: "#dd7e6b",
onClick: args => {
updateColor(args.source, args.item.color);
}
},
]
})
}
);
const schedulerRef = ref(null);
const loadReservations = () => {
const events = [
{
id: 1,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(7),
text: "Event 1",
color: "#6fa8dc"
},
{
id: 2,
resource: "R1",
start: DayPilot.Date.today().firstDayOfMonth().addDays(9),
end: DayPilot.Date.today().firstDayOfMonth().addDays(12),
text: "Event 2",
color: "#93c47d"
},
{
id: 3,
resource: "R3",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(6),
text: "Event 3",
color: "#6fa8dc"
},
{
id: 4,
resource: "R2",
start: DayPilot.Date.today().firstDayOfMonth().addDays(3),
end: DayPilot.Date.today().firstDayOfMonth().addDays(6),
text: "Event 4",
color: "#93c47d"
},
{
id: 5,
resource: "R3",
start: DayPilot.Date.today().firstDayOfMonth().addDays(7),
end: DayPilot.Date.today().firstDayOfMonth().addDays(10),
text: "Event 5",
color: "#f1c232"
},
{
id: 6,
resource: "R3",
start: DayPilot.Date.today().firstDayOfMonth().addDays(12),
end: DayPilot.Date.today().firstDayOfMonth().addDays(15),
text: "Event 6",
color: "#dd7e6b"
},
];
config.events = events;
};
const loadResources = () => {
const resources = [
{
name: "Group A", id: "GA", expanded: true, children: [
{name: "Resource 1", id: "R1", location: "Location 1"},
{name: "Resource 2", id: "R2", location: "Location 1"},
{name: "Resource 3", id: "R3", location: "Location 2"},
{name: "Resource 4", id: "R4", location: "Location 2", status: "locked"},
]
},
{
name: "Group B", id: "GB", expanded: true, children: [
{name: "Resource 5", id: "R5", location: "Location 3"},
{name: "Resource 6", id: "R6", location: "Location 3"},
{name: "Resource 7", id: "R7", location: "Location 4"},
{name: "Resource 8", id: "R8", location: "Location 4"},
]
}
];
config.resources = resources;
};
const updateColor = (e, color) => {
const scheduler = schedulerRef.value?.control;
e.data.color = color;
scheduler.events.update(e);
scheduler.message("Color updated");
};
onMounted(() => {
const scheduler = schedulerRef.value?.control;
loadResources();
loadReservations();
scheduler.message("Welcome!");
scheduler.scrollTo(DayPilot.Date.today().firstDayOfMonth());
});
</script>
History
October 1, 2024: Upgraded to DayPilot Pro for JavaScript 2024.4.6180. Additional row header columns defined. Styling updates.
November 30, 2023: Switched to Vue 3 Composition API, upgraded to DayPilot Pro for JavaScript 2023.4.5801.
June 3, 2021: Upgraded to DayPilot Pro for JavaScript 2021.2.5000; upgraded to Vue 3; using system fonts; switched to SVG icons.
December 5, 2020: Using package-based Vue 2 project, upgraded to DayPilot Pro for JavaScript 2020.4.4788.
September 24, 2019: Upgraded to DayPilot Pro for JavaScript 2019.3.4012.
February 9, 2018: Context menu added.
February 5, 2018: Initial release.