javascript scheduler drag drop event moving customization

In the JavaScript Scheduler component, you can control the drag and drop event moving using a real-time onEventMoving event handler. This event is fired whenever the target position changes.

The onEventMoving event handler lets you modify the behavior using the following properties:

  • args.allowed - disable the target position (depending on custom rules)

  • args.left - display an inline label, positioned to the left of the target shadow

  • args.right - display an inline label, positioned to the right of the target shadow

  • args.start - modify the start date/time of target shadow

  • args.end - modify the end date/time of the target shadow

This event is very flexible and lets you implement a number of custom rules and/or provide additional feedback during dragging.

Prevent Moving from Resource "A" to Resource "B"

This example prevents moving events from row "A" to row "B". To do this, it checks whether the event's original position (args.e.resource()) was in row "A" and whether the intended new position (args.resource) is row "B".

If these two conditions are met, the event handler modifies the HTML of the label displayed to the right of the target to display a message saying, "You can't move an event from resource A to B". Also, it disables a label displayed to the left of the target shadow using args.left.enabled = false.

Finally, it sets args.allowed to false. This forbids the relocation of the event from row "A" to row "B".

onEventMoving: (args) => {
    // don't allow moving from A to B
    if (args.e.resource() === "A" && args.resource === "B") {
        args.left.enabled = false;
        args.right.html = "You can't move an event from resource A to B";

        args.allowed = false;
    }
}

Prevent Overlaps in Resource "B"

This example checks to see if the target resource for the event move is "B" (args.resource === "B"). If it is, the event handler retrieves events in the target row within the time range specified by args.start and args.end.

If any events are found within this range (events.length > 0), this indicates that the event move would create an overlap with existing events in resource 'B'. To prevent this, the function hides the left-positioned label (args.left.enabled = false), and sets a right-positioned label message as "Overlaps forbidden for 'B' resource." (args.right.html = "Overlaps forbidden for 'B' resource."). This action informs the user about the overlap rule.

It cancels the event move by setting args.allowed to false, which prevents any event overlap from occurring in resource 'B'.

onEventMoving: (args) => {
    if (args.resource === "B") {
        const row = dp.rows.find(args.resource);
        const events = row.events.forRange(args.start, args.end);
        if (events.length > 0) {
            args.left.enabled = false;
            args.right.html = "Overlaps forbidden for 'B' resource.";

            args.allowed = false;
        }
    }
}

Prevent Dragging Events Out of the Visible Range

This example checks whether the end time of the moving event (args.end) exceeds the current visible end time (dp.visibleEnd()). If it does, the function enables and sets the left-positioned label with the message "You can't drag the event out of the visible range". Also, it disables the right-positioned label and sets args.allowed to false. This prevents the event from being moved beyond the visible end time.

The same mechanism is used to prevent moving an event before the visible start.

onEventMoving: (args) => {

  if (args.end > dp.visibleEnd()) {
      args.left.enabled = true;
      args.left.html = "You can't drag the event out of the visible range";
      args.right.enabled = false;
      args.allowed = false;
  }

  if (args.start < dp.visibleStart()) {
      args.right.enabled = true;
      args.right.html = "You can't drag the event out of the visible range";
      args.left.enabled = false;
      args.allowed = false;
  }
};

Adjusting the Target Position

This example moves the event to the first available slot if there are existing events at the target position.

It retrieves all events in the target row and checks whether the target position overlaps with any of them. If there is an overlap, it tries the next slot (it assumes that the cell duration is one day).

It also displays a label describing this automatic adjustment.

onEventMoving: args => {
  const except = args.e.data;
  const events = dp.rows.find(args.resource).events.all();

  let start = args.start;
  let end = args.end;
  let overlaps = events.some(function(item) {
      return item.data !== except && DayPilot.Util.overlaps(item.start(), item.end(), start, end);
  });

  while (overlaps) {
      start = start.addDays(1);
      end = end.addDays(1);

      overlaps = events.some(function(item) {
          return item.data !== except && DayPilot.Util.overlaps(item.start(), item.end(), start, end);
      });
  }

  args.start = start;
  args.end = end;

  args.left.enabled = false;
  args.right.html = "Start automatically moved to " + args.start.toString("d MMMM, yyyy");
}

Events Must Start on Workdays

This example checks if the start date of the event (args.start) falls on a weekend (where getDayOfWeek() == 0 corresponds to Sunday and getDayOfWeek() == 6 corresponds to Saturday). If the start day is a weekend, the function enters a loop, incrementing the start day by one (args.start = args.start.addDays(1)) until the start day is a workday.

onEventMoving: (args) => {
  // must start on a working day
  while (args.start.getDayOfWeek() == 0 || args.start.getDayOfWeek() == 6) {
      args.start = args.start.addDays(1);
  }
  args.left.enabled = false;
  args.right.html = "Events must start on a workday.";
};

Customized Snap-To-Grid

The built-in snap-to-grid feature aligns the selection with the grid cells. This example uses a custom rule - the cell size is set to one hour (scale property) but the event snaps to 5-minute segments during moving.

{
  scale: "Hour",
  snapToGrid: false,
  useEventBoxes: "Never",
  onEventMoving: (args) => {
    const offset = args.start.getMinutes() % 5;
    if (offset) {
      args.start = args.start.addMinutes(-offset);
      args.end = args.end.addMinutes(-offset);
    }

    args.left.enabled = true;
    args.left.html = args.start.toString("h:mm tt");
  },
  // ...
}

See also JavaScript Scheduler: Customized Snap-to-Grid tutorial.

Tutorials

ASP.NET WebForms

You can set the event handler using EventMovingJavaScript property.

<DayPilot:DayPilotScheduler
  ...
  EventMovingJavaScript="eventMoving(args);"
/>

<script>
function eventMoving(args) {
    // don't allow moving from A to B
    if (args.e.resource() === "A" && args.resource === "B") {
        args.left.enabled = false;
        args.right.html = "You can't move an event from resource A to B";

        args.allowed = false;
    }
};
</script>

ASP.NET MVC

@Html.DayPilotScheduler("dps", new DayPilotSchedulerConfig {
    BackendUrl = Url.Action("Backend", "Scheduler"),
    // ...
    EventMovingJavaScript = "onEventMoving(args)"
})


<script>
function eventMoving(args) {
    if (args.e.resource() === "A" && args.resource === "B") {
        args.left.enabled = false;
        args.right.html = "You can't move an event from resource A to B";

        args.allowed = false;
    }
};
</script>