Overview
The Vue resource calendar component displays resources (people, rooms, cars, tools) as columns.
It is built using the open-source Vue calendar from DayPilot Lite for JavaScript package.
You can switch the current day using a date picker that shows a calendar preview for three months.
Days with scheduled events are highlighted in the date picker.
You can define custom columns as necessary.
The resource calendar lets you schedule tasks, make reservations, and show resource utilization.
Vue calendar project is available for download.
The attached project uses Vue 3 and the Composition API to build the calendar.
License
Apache License 2.0
Resource Calendar in Vue.js
To use the DayPilot resource calendar component in your Vue application, start by installing the @daypilot/daypilot-lite-vue NPM package:
yarn install @daypilot/daypilot-lite-vue
Now you can add the resource calendar to your Vue application:
Create a new
ResourceCalendar
Vue component.Add
<DayPilotCalendar>
to the component template.Add a
[config]
attribute to<DayPilotCalendar>
and point it to aconfig
data property.Add the
config
object to the componentdata
.To enable the resource calendar mode, add
viewType: "Resources"
to the config.
To load resource calendar event data:
Add a
ref
attribute<DayPilotCalendar>
to store a reference to the Calendar component.Define
const calendar = ref(null);
and you will be able to access the DayPilot.Calendar object ascalendar.value.control
in your Vue application.To load events, call
calendar.value.control.update()
withevents
array in theoptions
parameter. You can use the update() method to update the Calendar component.
This is the first version of the ResourceCalendar.js
component that defines a Vue resource calendar with a basic configuration.
<template>
<DayPilotCalendar id="dp" :config="config" ref="calendar" />
</template>
<script>
import { ref, onMounted } from 'vue';
import { DayPilot, DayPilotCalendar, DayPilotNavigator } from '@daypilot/daypilot-lite-vue'
export default {
name: 'ResourceCalendar',
components: {
DayPilotCalendar,
},
setup() {
const calendar = ref(null);
const config = {
viewType: "Resources",
startDate: "2023-08-01",
};
const loadEvents = () => {
// placeholder for an HTTP call
const events = [
{
id: 1,
start: "2023-08-01T10:00:00",
end: "2023-08-01T11:00:00",
resource: "R3",
text: "Event 1",
barColor: "#6aa84f",
},
// ...
];
calendar.value.control.update({events});
};
onMounted(loadEvents);
return {
config,
calendar,
loadEvents,
};
},
}
</script>
Shows Resources as Columns in the Vue Calendar
As soon as the Vue calendar is initialized, we can load the columns:
onMounted(() => {
loadResources();
});
You need to remember that the calendar.value
object will only be accessible after the component is mounted. That’s why we have added our data-loading code to the onMounted()
lifecycle hook.
Our loadResources()
JavaScript function defines a set of resources statically to make things easier:
const columns = [
{name: "Resource 1", id: "R1"},
{name: "Resource 2", id: "R2"},
{name: "Resource 3", id: "R3"},
{name: "Resource 4", id: "R4"},
{name: "Resource 5", id: "R5"},
{name: "Resource 6", id: "R6"},
];
To load the columns, use the update() method of the Vue calendar component:
const loadResources = () => {
const columns = [
{name: "Resource 1", id: "R1"},
{name: "Resource 2", id: "R2"},
{name: "Resource 3", id: "R3"},
{name: "Resource 4", id: "R4"},
{name: "Resource 5", id: "R5"},
{name: "Resource 6", id: "R6"},
];
calendar.value.control.update({columns});
};
The update()
method loads the supplied data and refresh the calendar. The options
argument is an object with properties that will be updated. In this case, we only include the columns
property that will load the resources but you can update multiple properties at once if needed.
Load and Display Resource Calendar Events/Tasks
It is also necessary to load the event data (tasks, reservations) that will be displayed in the main calendar grid.
onMounted(() => {
// ...
loadEvents();
});
The loadEvents()
function is also very simple. And again, it uses the update()
method to load the data and update the calendar.
const loadEvents = () => {
// placeholder for an HTTP call
const events = [
{
id: 1,
start: "2023-08-01T10:00:00",
end: "2023-08-01T11:00:00",
resource: "R3",
text: "Event 1",
barColor: "#6aa84f",
},
{
id: 2,
start: "2023-08-01T13:00:00",
end: "2023-08-01T16:00:00",
resource: "R3",
text: "Event 2",
barColor: "#f1c232",
},
// ...
];
calendar.value.control.update({events});
};
Add New Events using Drag and Drop
The resource calendar supports adding new events using drag and drop. Users can select a time range for the selected resource (column) and enter details of the new event.
To enable this feature, add an onTimeRangeSelected event handler to the resource calendar config:
const calendarConfig = {
timeRangeSelectedHandling: "Enabled",
onTimeRangeSelected: async (args) => {
await createEvent(args.start, args.end, args.resource);
calendar.value.control.clearSelection();
},
// ...
};
The createEvent()
function opens a modal dialog that shows the selected resource, start and end time and lets you enter the event text.
The modal dialog is created using DayPilot.Modal.form() method that lets you create a JavaScript modal dialog with custom form fields programmatically (see also some modal dialog examples).
Our “new event” form displays four fields:
Text
Start
End
Resources
The DayPilot.Modal.form()
method can pre-fill the form fields from the supplied data
object. The data object uses data from the current calendar selection (start
, end
, resource
).
As soon as the modal dialog closes, you can access the form result using modal.result
property. It’s a copy of the original data
object - the properties are updated using the supplied form field values.
const createEvent = async (start, end, resource) => {
const form = [
{name: "Text", id: "text"},
{name: "Start", id: "start", type: "datetime", disabled: true},
{name: "End", id: "end", type: "datetime", disabled: true},
{name: "Resource", id: "resource", type: "select", options: calendar.value.control.columns.list}
];
const data = {
start,
end,
resource,
id: DayPilot.guid()
};
const modal = await DayPilot.Modal.form(form, data);
if (modal.canceled) {
return;
}
const e = modal.result;
calendar.value.control.events.add(e);
};
The events.add() method then adds the new event to the resource calendar.
Edit Resource Calendar Events
You can use the same approach to create the “edit” modal dialog.
To open the modal dialog on event click, it is necessary to add an onEventClick event handler to the resource calendar config.
const calendarConfig = {
onEventClick: (args) => {
editEvent(args.e);
},
// ...
};
The editEvent()
JavaScript function opens a modal dialog similar to the “new event” dialog from the previous chapter and updates the event using an events.update()
call.
const editEvent = async (e) => {
const form = [
{name: "Text", id: "text"},
{name: "Start", id: "start", type: "datetime", disabled: true},
{name: "End", id: "end", type: "datetime", disabled: true},
{name: "Resource", id: "resource", type: "select", options: calendar.value.control.columns.list}
];
const data = e.data;
const modal = await DayPilot.Modal.form(form, data);
if (modal.canceled) {
return;
}
calendar.value.control.events.update(modal.result);
};
Vue Date Picker with Free/Busy Highlighting
To make the date switching easier, we will add a date picker component that will display an overview of three months and let users change the current date easily. To learn more about the Vue date picker, please see the Vue Date Picker with Free/Busy Highlighting (Open-Source) tutorial. Here is a quick summary of the necessary steps:
The date picker can be added using <DayPilotNavigator>
component.
First, it’s necessary to update the layout so there are two independent columns. The left column will display the date picker component and the right column will display the resource calendar:
<template>
<div class="wrap">
<div class="left">
<DayPilotNavigator id="nav" :config="navigatorConfig" ref="navigator" />
</div>
<div class="content">
<DayPilotCalendar id="dp" :config="config" ref="calendar" />
</div>
</div>
</template>
The parent <div>
that is marked with wrap
CSS class uses display: flex
to show the child elements as columns:
<style>
.wrap {
display: flex;
}
.left {
margin-right: 10px;
}
.content {
flex-grow: 1;
}
</style>
Now we can configure the date picker:
const navigatorConfig = {
showMonths: 3,
skipMonths: 3,
selectMode: "Day",
startDate: "2023-08-01",
selectionDay: "2023-08-01",
onTimeRangeSelected: args => {
calendarConfig.startDate = args.day;
}
};
The onTimeRangeSelected event handler is fired when a user selects a date in the date picker. We will use this event handler to update the startDate
property of the calendarConfig
object.
In order to reload the resource calendar automatically, we need to wrap the calendarConfig
using the reactive()
method so Vue detects the changes automatically.
const calendarConfig = reactive({
viewType: "Resources",
startDate: "2023-08-01",
// ...
});
To highlight busy days, you can load the event data. Note that we have just extended the existing loadEvents()
function to load the existing data to the Navigator (date picker) as well. The event data structure used by both component is the same so there is no need to transform the calendar data items.
const loadEvents = () => {
// placeholder for an HTTP call
const events = [
{
id: 1,
start: "2023-08-01T10:00:00",
end: "2023-08-01T11:00:00",
resource: "R3",
text: "Event 1",
barColor: "#6aa84f",
},
{
id: 2,
start: "2023-08-01T13:00:00",
end: "2023-08-01T16:00:00",
resource: "R3",
text: "Event 2",
barColor: "#f1c232",
},
// ...
];
// ...
navigator.value.control.update({events});
};
The navigator
ref provides access to the DayPilot.Navigator object:
const navigator = ref(null);