Overview

  • How to configure the JavaScript Scheduler to allow a time range selection in multiple adjacent rows.
  • Based on rectangle selection feature.
  • Requires DayPilot Pro for JavaScript 2020.2.4488 or higher
  • 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.

Live Demo

JavaScript Scheduler: Rectangle Selection

javascript-scheduler-time-range-rows-rectangle.png

In addition to the standard drag and drop operations, the Scheduler supports selecting a custom rectangle area. It has to be enabled using rectangleSelectHandling property.

Selecting Events using the Rectangle

It can be used to select all events in the rectangle (set rectangleSelectHandling to "EventSelect").

Shift + drag will activate the selecting and the corresponding rectangle will be displayed:

javascript-scheduler-time-range-rows-rectangle-event-selection.png

The underlying events will be selected when you release the mouse button:

javascript-scheduler-time-range-rows-rectangle-event-selection-complete.png

Selecting a Time Range

We will use this feature to create a custom time range selection that spans multiple adjacent rows.

First, we enable the rectangle selection, without the default action:

rectangleSelectHandling: "Enabled"

Then we need to create an onRectangleSelecting event handler that will create/update the time range multi-selection:

onRectangleSelecting: function(args) {
  dp.multirange.clear();
  args.resources.forEach(function(r) {
    dp.multirange.add({start: args.start, end: args.end, resource: r});
  });
},

We can hide the rectangle by adding args.visible = true; to the event handler:

onRectangleSelecting: function(args) {
  args.visible = false;
  // ...
},

Handling the Multi-Row Selection

javascript-scheduler-time-range-rows-selection.png

Normally, you would use onTimeRangeSelect event to handle time-range selections. In this case, this event is not fired because we are creating the time range using the API.

Instead, we will use onRectangleSelect event handler which is fired when the rectangle selection is complete (when the user releases the mouse button).

onRectangleSelect: function(args) {
  dp.multirange.get().forEach(function(range) {
    if (!range.allowed) {
      return;
    }
    dp.events.add({
      start: range.start,
      end: range.end,
      resource: range.resource,
      text: "Event",
      id: DayPilot.guid()
    })
  });

  dp.multirange.clear();
}

In this example, we create a new event in rows where it is allowed (range.allowed == true) and clear the selection.

Full Source Code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JavaScript Scheduler: Select a Time Range for Multiple Rows</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/85404/javascript-scheduler-select-a-time-range-for-multiple-rows'>JavaScript Scheduler: Select a Time Range for Multiple Rows</a></h1>
  <div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React/Vue</div>
</div>

<div class="main">
  <div class="space">Use Shift+drag to select a time range for multiple rows.</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: DayPilot.Date.today().daysInMonth(),
    startDate: DayPilot.Date.today().firstDayOfMonth(),
    timeRangeSelectedHandling: "Enabled",
    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
        }));
      });
    },
    rectangleSelectMode: "Free",
    rectangleSelectHandling: "EventSelect",
    allowEventOverlap: false,
    onRectangleSelecting: function(args) {
      args.visible = false;
      dp.multirange.clear();
      args.resources.forEach(function(r) {
        dp.multirange.add({start: args.start, end: args.end, resource: r});
      });
    },
    onRectangleSelect: function(args) {
      dp.multirange.get().forEach(function(range) {
        if (!range.allowed) {
          return;
        }
        dp.events.add({
          start: range.start,
          end: range.end,
          resource: range.resource,
          text: "Event",
          id: DayPilot.guid()
        })
      });

      dp.multirange.clear();
    }
  });
  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.events.list = [
    { text: "Event 1", start: "2020-06-12T00:00:00", end: "2020-06-17T00:00:00", resource: "R3", id: 1},
    { text: "Event 2", start: "2020-06-16T00:00:00", end: "2020-06-21T00:00:00", resource: "R5", id: 2},
    { text: "Event 3", start: "2020-06-10T00:00:00", end: "2020-06-16T00:00:00", resource: "R7", id: 3},
  ];
  dp.init();
</script>

</body>
</html>