Overview
Make all-day events displayed by the JavaScript Calendar component draggable using the HTML5 drag and drop API.
Activate Calendar cells as drop targets.
This customization will allow dragging all-day events to a specific time of day.
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.
The How to Drag All-Day Events to the Calendar Grid
The JavaScript Calendar component from DayPilot Pro for JavaScript package includes built-in support for many drag and drop scenarios.
You can extend the calendar functionality using the native HTML5 drag and drop API and add support for custom drag and drop scenarios.
See also related JavaScript Scheduler tutorial that use a similar approach to support dragging desktop items to the Scheduler (JavaScript Scheduler: Dragging Files and Other Items from Desktop) and dragging external items to events (JavaScript Scheduler: Events as Drag and Drop Target).
In this tutorial, we will use the drag and drop API to support dragging all-day events from a special row at the top of the calendar to the main Calendar grid.
How to Make All-Day Events Draggable
The calendar all-day events are displayed in a special row at the top of the Calendar control and they are not draggable. You can use the native HTML5 drag and drop API to enable dragging them to a selected calendar cell.
Two steps are necessary:
add a
draggable
attribute to the all-day event element with a value set to"true"
add a
dragstart
event handler that will publish the source event data usingdataTransfer
property
You can do this using onAfterEventRender event handler which provides access to the all-day event DOM element (args.div
).
onAfterEventRender: args => {
if (args.e.data.allday) {
args.div.setAttribute("draggable", "true");
args.div.addEventListener("dragstart", ev => {
const data = {
id: args.e.id(),
name: args.e.text()
};
ev.dataTransfer.setData("daypilot/allday", JSON.stringify(data));
});
}
},
How to Use Calendar Grid Cells as a Drop Target
To activate the Calendar grid cells as drop targets, we will use the onAfterCellRender event handler and add a custom handler for the drop
event.
The drop
event handler reads the data associated with the dragged item using ev.dataTransfer.getData()
. If the data type is recognized, it finds the source event objects using events.find() and updates the event start, end, and all-day status.
onAfterCellRender: args => {
args.div.addEventListener("drop", ev => {
ev.preventDefault();
ev.stopPropagation();
const daypilotJson = ev.dataTransfer.getData("daypilot/allday");
if (daypilotJson) {
const data = JSON.parse(daypilotJson);
const e = dp.events.find(data.id);
if (e) {
e.data.allday = false;
e.data.start = args.cell.start;
e.data.end = args.cell.end;
dp.events.update(e);
}
}
});
}
How to Highlight the Target Calendar Cells During Dragging
To provide a visual feedback during dragging, you can use dragover
and dragleave
event handlers to add a custom CSS class that highlights the cell:
onAfterCellRender: args => {
args.div.addEventListener("dragover", ev => {
const hasMyType = ev.dataTransfer.types.some(function(type) { return type === "daypilot/allday"; });
if (hasMyType) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move";
}
else {
ev.stopPropagation();
ev.preventDefault();
ev.dataTransfer.dropEffect = 'copy';
}
args.div.firstChild.classList.add("dragging-over");
});
args.div.addEventListener("dragleave", ev => {
args.div.firstChild.classList.remove("dragging-over");
});
args.div.addEventListener("drop", ev => {
// ...
args.div.firstChild.classList.remove("dragging-over");
// ...
});
}
The .dragging-over
CSS class adds a red border to the cell:
<style>
#dp .calendar_default_cell_inner.dragging-over {
border: 2px solid red;
}
</style>