Features

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.

Live Demo

Using Event Versions to Display the Allowed Range

javascript-scheduler-highlight-target-drag-and-drop-date-range.png

The JavaScript Scheduler component can display one or more previous versions of each event. The event versions are read-only bars that are displayed outside of the main event box. The versions can be displayed above or below the main event (see eventVersionPosition property). The version elements are styled separately using CSS - the default theme uses a striped background to visually separate them from the main events.

The main purpose of this feature is to display the original plan in addition to the current position so the users can see how the plan has changed.

However, it can also be used to display any date range related to the main event. In this example, we will use it to display a date range limit that will be applied during drag and drop moving of the main event.

The event versions are defined using versions property of the event data object:

dp.events.list = [{
  start: "2019-12-05T00:00:00",
  end: "2019-12-08T00:00:00",
  id: 1,
  resource: "R2",
  text: "Event 1",
  versions: [
    {start:"2019-12-02T00:00:00", end: "2019-12-12T00:00:00", barHidden: true }
  ]
}];

Limiting the Drag and Drop Range

javascript-scheduler-limit-target-drag-and-drop-date-range.png

Now that the allowed range is visible we need to actually limit the target position during drag and drop. This can be done using the real-time onEventMoving event handler.

The onEventMoving event handler allows adjusting the target position using args.start and args.end parameters. We will check the current position with the range defined with the first version (args.e.data.versions[0]) and recalculate the args.start and args.end values if they fall outside the predefined boundaries.

This will force the target position to stay within the range during drag and drop.

dp.onEventMoving = function(args) {
  var version = args.e.data.versions && args.e.data.versions[0];
  if (!version) {
    return;
  }
  var vStart = new DayPilot.Date(version.start);
  var vEnd = new DayPilot.Date(version.end);
  if (args.start < vStart) {
    var diff = vStart.getTime() - args.start.getTime();
    args.start = vStart;
    args.end = args.end.addTime(diff);
  }
  if (args.end > vEnd) {
    var diff = args.end.getTime() - vEnd.getTime();
    args.end = vEnd;
    args.start = args.start.addTime(-diff);
  }
};

Another option would be to simply mark the target position as forbidden using args.allowed:

javascript-scheduler-limit-target-drag-and-drop-date-range-forbidden.png

This method is easier as it doesn't require any additional calculations. If the target position is outside of the allowed range it will be displayed in red color (calendar_default_shadow_forbidden CSS class is applied). The Scheduler won't fire onEventMove events if the event is dropped at this position.

dp.onEventMoving = function(args) {
  var version = args.e.data.versions && args.e.data.versions[0];
  if (!version) {
    return;
  }
  var vStart = new DayPilot.Date(version.start);
  var vEnd = new DayPilot.Date(version.end);
  if (args.start < vStart) {
    args.allowed = false;
  }
  if (args.end > vEnd) {
    args.allowed = false;
  }
};

Full Source Code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JavaScript Scheduler: Limited Drag and Drop Range</title>

  <style type="text/css"> /* ... */ </style>

  <!-- DayPilot library -->
  <script src="js/daypilot/daypilot-all.min.js"></script>
</head>
<body>
<div class="header">
  <h1><a href='https://code.daypilot.org/23016/javascript-scheduler-limited-drag-and-drop-range'>JavaScript Scheduler: Limited Drag and Drop Range</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="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-12-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
        }));
      });
    },
    treeEnabled: true,
  });
  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"},
    {name: "Resource 8", id: "R8"},
    {name: "Resource 9", id: "R9"},
  ];
  dp.eventVersionsEnabled = true;
  dp.eventVersionsReserveSpace = true;
  dp.eventVersionHeight = 10;
  dp.events.list = [
    {
      start: "2019-12-05T00:00:00",
      end: "2019-12-08T00:00:00",
      id: 1,
      resource: "R2",
      text: "Event 1",
      versions: [{ start: "2019-12-02T00:00:00", end: "2019-12-12T00:00:00", barHidden: true }]
    },
    {
      start: "2019-12-06T00:00:00",
      end: "2019-12-09T00:00:00",
      id: 2,
      resource: "R4",
      text: "Event 2",
      versions: [{ start: "2019-12-04T00:00:00", end: "2019-12-15T00:00:00", barHidden: true }]
    }
  ];
  dp.onEventMoving = function(args) {
    var version = args.e.data.versions && args.e.data.versions[0];
    if (!version) {
      return;
    }
    var vStart = new DayPilot.Date(version.start);
    var vEnd = new DayPilot.Date(version.end);
    if (args.start < vStart) {
      var diff = vStart.getTime() - args.start.getTime();
      args.start = vStart;
      args.end = args.end.addTime(diff);
    }
    if (args.end > vEnd) {
      var diff = args.end.getTime() - vEnd.getTime();
      args.end = vEnd;
      args.start = args.start.addTime(-diff);
    }
  };
  dp.init();
</script>

</body>
</html>