In DayPilot Pro, validate the target position during dragging using onEventMoving. Real-time checks must be synchronous. Both Pro and Lite support validation on drop using onEventMove.

This example prevents moving an event onto a weekend, including events spanning multiple dates.

onEventMoving: (args) => {
    const { start, end } = args;

    const isWeekend = (date) => {
        const dayOfWeek = date.getDayOfWeek();
        return dayOfWeek === 0 || dayOfWeek === 6;  // Sunday or Saturday
    };

    let currentDate = start.getDatePart();
    let overlapsWeekend = false;

    while (currentDate < end) {
        if (isWeekend(currentDate)) {
            overlapsWeekend = true;
            break;
        }
        currentDate = currentDate.addDays(1);
    }

    if (overlapsWeekend) {
        args.allowed = false;
    }
},

Built-in Move Validation

When eventMoveSkipNonBusiness is enabled, moving an event preserves its number of business hours. The original resource’s calendar determines that duration; the target resource’s calendar determines the new end. Since Pro version 2026.4.7083, custom business hours also apply to dates outside the visible area and to frozen rows.

The Scheduler rejects a move if the source has zero business duration or the target lacks enough business time within its row and timeline bounds. It displays a forbidden shadow and prevents the drop. It does not add an explanation label automatically.

For optional feedback, inspect read-only args.invalid in onEventMoving:

onEventMoving: args => {
  if (args.invalid) {
    args.right.enabled = true;
    args.right.html = "This move cannot be completed here.";
  }
}

args.invalid is read-only and is also true if any event in a multi-move has an invalid target. Use it to explain why a drop is unavailable; use args.allowed = false for your own restrictions. Setting args.allowed = true cannot permit an invalid drop.

On drop, you can validate the target position using the onEventMove event handler and cancel it if doesn’t meet the rules.

This validation can be asynchronous, and you can call external services (e.g. a server-side API endpoint) to perform the validation.

onEventMove: async (args) => {
    args.async = true;
    const params = {
      id: args.e.id(),
      start: args.newStart,
      end: args.newEnd,
      resource: args.newResource
    };
    try {
const {data} = await DayPilot.Http.post("/api/checkMoveTarget", params);

    if (data.error) {
        dp.message(data.message);
        args.preventDefault();
    }
    
} catch {
  args.preventDefault();
  await DayPilot.Modal.alert("The change could not be saved or validated.");
} finally { args.loaded(); }
},

API: onEventMove.

The framework examples validate on drop: onEventMove checks args.newResource and calls args.preventDefault() for Room B. The event stays in its original position.

The framework examples use DayPilot Pro. For installation, see the Angular, React or Vue Scheduler guide.

Angular

import {Component} from "@angular/core";
import {DayPilot, DayPilotModule} from "daypilot-pro-angular";

@Component({
  selector: "app-scheduler-example",
  standalone: true,
  imports: [DayPilotModule],
  template: `
    
    <daypilot-scheduler [config]="config"></daypilot-scheduler>
  `
})
export class SchedulerExampleComponent {
  config: DayPilot.SchedulerConfig = {
    startDate: "2026-11-01",
    days: 30,
    scale: "Day",
    timeHeaders: [{groupBy: "Month"}, {groupBy: "Day", format: "d"}],
    resources: [{id: "A", name: "Room A"}, {id: "B", name: "Room B"}],
    events: [{id: 1, text: "Planning", resource: "A", start: "2026-11-03", end: "2026-11-06"}, {id: 2, text: "Delivery", resource: "B", start: "2026-11-08", end: "2026-11-11"}],
    onEventMove: args => { if (args.newResource === "B") { args.preventDefault(); DayPilot.Modal.alert("Room B is unavailable."); } }
  };

}

React

import React from "react";
import {DayPilot, DayPilotScheduler} from "daypilot-pro-react";

export default function SchedulerExample() {

  return <div>

    <DayPilotScheduler
      startDate={"2026-11-01"}
      days={30}
      scale={"Day"}
      timeHeaders={[{groupBy: "Month"}, {groupBy: "Day", format: "d"}]}
      resources={[{id: "A", name: "Room A"}, {id: "B", name: "Room B"}]}
      events={[{id: 1, text: "Planning", resource: "A", start: "2026-11-03", end: "2026-11-06"}, {id: 2, text: "Delivery", resource: "B", start: "2026-11-08", end: "2026-11-11"}]}
      onEventMove={args => { if (args.newResource === "B") { args.preventDefault(); DayPilot.Modal.alert("Room B is unavailable."); } }}
    />
  </div>;
}

Vue

<script setup>
import {DayPilot, DayPilotScheduler} from "daypilot-pro-vue";

const startDate = "2026-11-01";
const days = 30;
const scale = "Day";
const timeHeaders = [{groupBy: "Month"}, {groupBy: "Day", format: "d"}];
const resources = [{id: "A", name: "Room A"}, {id: "B", name: "Room B"}];
const events = [{id: 1, text: "Planning", resource: "A", start: "2026-11-03", end: "2026-11-06"}, {id: 2, text: "Delivery", resource: "B", start: "2026-11-08", end: "2026-11-11"}];
const onEventMove = args => { if (args.newResource === "B") { args.preventDefault(); DayPilot.Modal.alert("Room B is unavailable."); } };

</script>

<template>
  <div>

    <DayPilotScheduler
      :startDate="startDate"
      :days="days"
      :scale="scale"
      :timeHeaders="timeHeaders"
      :resources="resources"
      :events="events"
      :onEventMove="onEventMove"
    />
  </div>
</template>

Availability

Availability of this feature in DayPilot editions:

ProductLitePro
DayPilot for JavaScript
DayPilot for ASP.NET WebForms
DayPilot for ASP.NET MVC
DayPilot for Java