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.

  • 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.

The How to Drag All-Day Events to the Calendar Grid

The JavaScript Calendar component from DayPilot Pro 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

javascript calendar 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 using dataTransfer 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

javascript calendar all day drag 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>