Overview

Use HTML5 drag and drop API to drag events from events to a target outside of the JavaScript Scheduler component:

  • Add one or more icons to the event (using active areas) and make them draggable.

  • Use a custom drop target.

  • Make the event data accessible to the drop event handler.

The sample project 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.

Add Draggable Items to Scheduler Events

javascript scheduler drag items out of events drag handle

We will use event active areas to add the items. This is convenient because we it will let us specify the position and styling easily but you can use plain HTML as well.

Lets add a simple green square to the right side of the event using onBeforeEventRender:

onBeforeEventRender: function(args) {
  args.data.areas = [
    {
      right: 5,
      top: 10,
      height: 15,
      width: 15,
      backColor: "#6aa84f",
      cssClass: "draggable",
      style: "cursor: move"
    }
  ]
},

javascript scheduler drag items out of events start dragging

As soon as the event is rendered we can make the element draggable. We have marked the active area using "draggable" CSS class so we can find and activate it in onAfterEventRender event handler:

onAfterEventRender: function(args) {

  var data = args.e.data;
  var area = args.div.getElementsByClassName("draggable")[0];

  area.setAttribute("draggable", "true");
  area.addEventListener("dragstart", function(ev) {
    console.log("dragstart");
    ev.dataTransfer.setData("daypilot/external-item", JSON.stringify(data));
  });
  area.addEventListener("mousedown", function(ev) {
    ev.stopPropagation();
  });
}

We have attached the event data object (serialized as a JSON string) to the dragged object using event.dataTransfer.SetData() method.

We also need to stop the propagation of "mousedown" event to prevent event moving (which is enabled by default; we want to keep it enabled for the rest of the event box).

Adding the External Drop Target

javascript scheduler drag items out of events drop target

Our drop target is a simple <div> element:

<div id="drop">You can drop the green square from events here.</div>

We will add some styling using CSS to highlight it:

#drop {
  height: 100px;
  box-sizing: border-box;
  border: 1px solid #c0c0c0;
  background-color: #f3f3f3;
  color: #333;
  padding: 10px;
  margin: 20px 0px;
}

The drop target needs to be activated as well:

function initDropTarget() {
  var drop = document.getElementById("drop");
  drop.ondragover = function(ev) {
    ev.preventDefault();
    ev.dataTransfer.dropEffect = "copy";
  };
  drop.ondrop = function(ev) {
    var data = ev.dataTransfer.getData("daypilot/external-item");
    var ev = JSON.parse(data);
    console.log("drop data", ev);

    drop.innerText = data;
  };
}

In the "drop" event handler, we can access the original event data using DataTransfer.getData() method.

In our event handler, we deserialize the object using JSON.parse() and print it to the console. In addition to that, the full source data string will be displayed in the drop target.

Full Source Code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>JavaScript Scheduler: Dragging Items from Events</title>

  <!-- ... global css omitted -->

  <style>
    #drop {
      height: 100px;
      box-sizing: border-box;
      border: 1px solid #c0c0c0;
      background-color: #f3f3f3;
      color: #333;
      padding: 10px;
      margin: 20px 0px;
    }
  </style>

  <!-- DayPilot library -->
  <script src="js/daypilot/daypilot-all.min.js"></script>
</head>
<body>
<div class="header">
  <h1><a href='https://code.daypilot.org/30579/javascript-scheduler-dragging-items-from-events'>JavaScript Scheduler: Dragging Items from Events</a></h1>
  <div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React</div>
</div>

<div class="main">
  <div id="drop">You can drop the green square from events here.</div>
  <div id="dp"></div>
  <div class="generated">Generated using <a href="https://builder.daypilot.org/">DayPilot UI Builder</a>.</div>
</div>


<script>
  var dp = new DayPilot.Scheduler("dp", {
    timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}],
    scale: "Day",
    days: 31,
    startDate: "2019-08-01",
    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
        }));
      });
    },
    onBeforeEventRender: function(args) {
      args.data.areas = [
        {
          right: 5,
          top: 10,
          height: 15,
          width: 15,
          backColor: "#6aa84f",
          cssClass: "draggable",
          style: "cursor: move"
        }
      ]
    },
    onAfterEventRender: function(args) {

      var data = args.e.data;
      var area = args.div.getElementsByClassName("draggable")[0];

      area.setAttribute("draggable", "true");
      area.addEventListener("dragstart", function(ev) {
        console.log("dragstart");
        ev.dataTransfer.setData("daypilot/external-item", JSON.stringify(data));
      });
      area.addEventListener("mousedown", function(ev) {
        ev.stopPropagation();
      });
    }
  });
  dp.resources = [
    {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"},
    {name: "Resource 7", id: "R7"},
  ];
  dp.events.list = [
    {
      start: "2019-08-03",
      end: "2019-08-10",
      id: 1,
      text: "Event 1",
      resource: "R2"
    }
  ];
  dp.init();


  function initDropTarget() {
    var drop = document.getElementById("drop");
    drop.ondragover = function(ev) {
      ev.preventDefault();
      ev.dataTransfer.dropEffect = "copy";
    };
    drop.ondrop = function(ev) {
      var data = ev.dataTransfer.getData("daypilot/external-item");
      var ev = JSON.parse(data);
      console.log("drop data", ev);

      drop.innerText = data;
    };

  }

  initDropTarget();

</script>

</body>
</html>