Features

  • How to disable custom date/time range and prevent drag and drop operations (JavaScript Scheduler component).

  • Multiple disabled ranges per row supported

  • Independent data for each Scheduler row

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.

Live Demo

Disabled Cells

The JavaScript Scheduler component supports disabling cells for drag and drop operations. The users will not be able to create new events on top of the disabled cells. It will not be possible to move or resize existing events to the disabled areas.

html5 scheduler grid disabled grid cells

The disabling works on cell level. To disable a cell, set args.cell.disabled to true in onBeforeCellRender event handler:

dp.onBeforeCellRender = function(args) {
  if (args.cell.start < new DayPilot.Date("2021-02-27") || args.cell.resource === "D") {
      args.cell.disabled = true;
      args.cell.backColor = "#ccc";
  }
};

However, the Scheduler is flexible enough to allow finer control of the disabled ranges. This tutorial shows how to create a custom disabled date/time range that is not aligned with the grid cells.

Disabled Range Data

We will define the disabled range data using disabled property of the resources array when loading resources. This is a custom property and you can change its name as needed.

The disabled property holds an array of objects, each with start, end and backColor property defined:

dp.resources = [
  {name: "Resource 1", id: "R1", disabled: [
      { start: "2021-12-03T12:00:00", end: "2021-12-05T12:00:00", backColor: "#d9ead3"}
    ]},
  {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"}
];

Partially Disabled Cells: Highlighting

javascript scheduler highlighting custom range

In order to highlight the disabled areas, we will use onBeforeCellRender event handler.

The event handler checks if there are any disabled ranges defined for the current row:

onBeforeCellRender: function(args) {
  var dp = this;

  var row = dp.rows.find(args.cell.resource);
  var disabled = row.data.disabled;
  if (!disabled) {
    return;
  }
  // ...

}

Then it looks for ranges that overlap the current cell:

  var item = disabled.map(function(item) {
    return {
      start: new DayPilot.Date(item.start),
      end: new DayPilot.Date(item.end),
      backColor: item.backColor
    };
  }).find(function(item) {
    return DayPilot.Util.overlaps(item.start, item.end, args.cell.start, args.cell.end);
  });

If an overlapping range is found, it checks whether the area covers the whole cell or just a part of it. For performance reasons, it uses args.cell.backColor to set the cell background for the whole cell.

For partial overlaps, it inserts an active area to highlight the affected part of the cell:

  if (item) {
    var fullOverlap = item.start <= args.cell.start && item.end >= args.cell.end;
    if (fullOverlap) {
      args.cell.backColor = item.backColor;
    }
    else {
      args.cell.areas = [
        { start: item.start, end: item.end, top: 0, bottom: 0, backColor: item.backColor}
      ];
    }
  }

The complete onBeforeCellRender event handler:

onBeforeCellRender: function(args) {
  var dp = this;

  var row = dp.rows.find(args.cell.resource);
  var disabled = row.data.disabled;
  if (!disabled) {
    return;
  }
  var item = disabled.map(function(item) {
    return {
      start: new DayPilot.Date(item.start),
      end: new DayPilot.Date(item.end),
      backColor: item.backColor
    };
  }).find(function(item) {
    return DayPilot.Util.overlaps(item.start, item.end, args.cell.start, args.cell.end);
  });

  if (item) {
    var fullOverlap = item.start <= args.cell.start && item.end >= args.cell.end;
    if (fullOverlap) {
      args.cell.backColor = item.backColor;
    }
    else {
      args.cell.areas = [
        { start: item.start, end: item.end, top: 0, bottom: 0, backColor: item.backColor}
      ];
    }
  }
}

Partially Disabled Cells: Preventing Drag and Drop

In addition to highlighting the disabled areas, it's also necessary to prevent drag and drop operations. That can be done using the real-time drag and drop events:

The logic of all event handlers is identical: It looks for disabled areas using disabled property of the resource object and it checks for overlap with the current drag and drop target. If an overlap is found, the current target is marked as forbidden using args.allowed.

Creating events (time range selecting):

onTimeRangeSelecting: function(args) {
  var disabled = args.row.data.disabled;
  if (!disabled) {
    return;
  }

  var item = disabled.map(function(item) {
    return {
      start: new DayPilot.Date(item.start),
      end: new DayPilot.Date(item.end)
    };
  }).find(function(item) {
    return DayPilot.Util.overlaps(item.start, item.end, args.start, args.end);
  });

  if (item) {
    args.allowed = false;
  }

}

Moving events:

onEventMoving: function(args) {
  var disabled = args.row.data.disabled;
  if (!disabled) {
    return;
  }

  var item = disabled.map(function(item) {
    return {
      start: new DayPilot.Date(item.start),
      end: new DayPilot.Date(item.end)
    };
  }).find(function(item) {
    return DayPilot.Util.overlaps(item.start, item.end, args.start, args.end);
  });

  if (item) {
    args.allowed = false;
  }
}

Resizing events:

onEventResizing: function(args) {
  var disabled = args.row.data.disabled;
  if (!disabled) {
    return;
  }

  var item = disabled.map(function(item) {
    return {
      start: new DayPilot.Date(item.start),
      end: new DayPilot.Date(item.end)
    };
  }).find(function(item) {
    return DayPilot.Util.overlaps(item.start, item.end, args.start, args.end);
  });

  if (item) {
    args.allowed = false;
  }
}