javascript html5 scheduler drag and drop moving

The Scheduler events can be moved using drag and drop. This functionality is enabled by default.

Event handling

As soon as the user drops the event at the target position, two events are fired:

These events let you handle the server-side notification.

  • The onEventMove event is fired before the default action.

  • The default action is set using the evenMoveHandling property. The default value is "Update" which means the event will be moved to the new location and the Scheduler UI will be updated.

  • The onEventMoved event is fired after the default action.

You can use the onEventMove event handler to perform additional checks and cancel the default action if needed:

  • ask the user for confirmation

  • check the server asynchronously to verify that the business rules are met

  • decide what action to perform, depending on the status of modifier keys

You can also forbid moving of of individual events using the onBeforeEventRender event handler (see event customization):

  • completely disable moving

  • only allow moving in the vertical or horizontal direction (see limit event moving)

You can also perform additional actions in these event handlers that update related events:

Example: Ask for a confirmation using a modal dialog

This example uses DayPilot.Modal.confirm() to display a modal dialog that asks for confirmation. If you cancel the confirmation dialog, the event will not be moved - the default action is canceled using args.preventDefault() method.

The DayPilot.Modal.confirm() method is asynchronous (it returns a Promise). That means it is necessary to switch to the async mode using args.async = true (otherwise the delayed args.preventDefault() call would be ignored).

You can replace the basic DayPilot.Modal.confirm() dialog with a custom dialog created using DayPilot.Modal.form().

onEventMove: async (args) => {
  args.async = true;
  const modal = await DayPilot.Modal.confirm("Do you really want to move this event?");
  if (modal.canceled) {
      args.preventDefault();
  }
  args.loaded();
}

Example: Display a message when moving is completed

In the onEventMoved event handler, you can display a confirmation using the built-in message bar.

onEventMoved: (args) => {
  dp.message("Moved: " + args.e.text());
}

Drag handle

Events can be dragged by pressing a mouse button anywhere in the event (except for the resize margins on the left and on the right which activate drag and drop event resizing).

You can disable the built-in mechanism and use a custom drag handle.

Touch devices

Event moving is also supported on touch devices.

In order to activate event moving, use the tap-and-hold gesture. The timeout needed for event moving activations can be adjusted using tapAndHoldTimeout property. By default, it uses the value of 300 (ms).

To provide a visual guide on touch devices, you can also create a custom drag handle using active areas. This way you can add an icon that will activate an event moving on simple tap (without the need to hold the finger for the specified time).

Real-time moving customization

Once the moving mode is activated, the Scheduler will display a shadow at the target location:

javascript scheduler event moving target shadow

You can customize the moving using the onBeforeEventMoving event handler. You can use this event to to implement the following features:

  • customize the shadow appearance (CSS, HTML)

  • dynamically calculate whether the target position is allowed

  • adjust the target position and duration

  • display custom labels next to the target shadow

You also can define a specific date range for each event, indicating the time frame within which the event can be rescheduled or moved.

While being dragged, the source event will be marked with *_scheduler_defaut_event_source CSS class. By default, it makes the source event semi-transparent using opacity CSS style.

Target position indicators

The Scheduler can display in-line indicators that display the current start/end date of the shadow.

Moving multiple events at once

It is possible to move multiple events at once:

See also JavaScript Scheduler: Copy Multiple Events.

Dragging events from an external source

You can drag external items to the Scheduler:

Copy events using drag and drop

With a few tweaks, it is possible to use this feature to make copies of existing events instead of moving them.

Skip non-business hours/days

The Scheduler can hide non-business hours from the timeline and you can configure event moving to extend the event duration accordingly (to exclude the hidden hours).

Undo/Redo

You can extend the functionality to save a history of changes that will let users perform undo and redo actions.

JavaScript Scheduler

This JavaScript Scheduler example uses onEventMove to update the event position using an HTTP call to an API endpoint. It waits for the response, updates the UI (the default action is set to "Update") and displays a confirmation message using onEventMoved.

<div id="dp"></div>
<script type="application/javascript">
  const dp = new DayPilot.Scheduler("dp", {
    eventMoveHandling: "Update",
    onEventMove: async (args) => {
      args.async = true;      

      const id = args.e.data.id;
      const params = {
        start: args.newStart,
        end: args.newEnd,
        resource: args.newResource
      };
      const {data} = await DayPilot.Http.put(`/api/events/${id}`, params);
      args.loaded();
    },
    onEventMoved: args => {
      dp.message("Event sucessfuly moved.");
    },
    // ...
  });
  dp.init();
</script>

Angular Scheduler

In the Angular Scheduler component, you can specify the event handlers using the config object.

This example submits the event position change using a PUT HTTP call to /api/events/{id} in onEventMove. The processing is switched to asynchronous mode using args.async = true. That will postpone further processing (including the default action) until args.loaded() is called. In onEventMoved, the Scheduler displays a confirmation message using the built-in message bar.

import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilot, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'scheduler-component',
  template: `<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>`,
  styles: [``]
})
export class SchedulerComponent implements AfterViewInit {

  @ViewChild('scheduler')
  scheduler!: DayPilotSchedulerComponent;

  events: DayPilot.EventData[] = [];

  config: DayPilot.SchedulerConfig = {
    eventMoveHandling: "Update",
    onEventMove: (args) => {
      args.async = true;
      const url = `/api/events/${args.e.data.id}`;
      this.http.put(url, args.e.data).subscribe(response => {
        args.loaded();
      }, error => {
        args.control.message("Error updating event on server: " + error);
      });
    },
    onEventMoved: (args) => {
      args.control.message("Event updated on server: " + args.e.text());
    },
    // ...
  };

  constructor(private http: HttpClient) {}

  ngAfterViewInit(): void {
    this.http.get('/api/resources').subscribe(result => {
      this.config.resources = result;
    });

    const from = this.scheduler.control.visibleStart();
    const to = this.scheduler.control.visibleEnd();

    this.http.get(`/api/events?start=${from}&end=${to}`).subscribe(result => {
      this.events = result;
    });
  }
}


ASP.NET WebForms

Drag and drop event moving is disabled by default.

It can be enabled using EventMoveHandling property. It has to be set to one of the following values:

  • CallBack

  • PostBack

  • Notify

  • JavaScript

PostBack event handling type will fire a server-side event handler (EventMove) using a PostBack (or partial AJAX PostBack if the scheduler is inside an UpdatePanel).

CallBack event handling type will fire a server-side event handler (EventMove) using an AJAX callback. CallBack is much faster than PostBack (and partial PostBack).

Notify event handling type will update the scheduler on the client immediately and then notify the server (EventMove) using an AJAX callback. Notify is much faster than CallBack.

JavaScript event handling will fire the JavaScript code specified in EventMoveJavaScript.

Server-Side Handler

<DayPilot:DayPilotScheduler runat="server" id="DayPilotScheduler1"
  ...
  EventMoveHandling = "CallBack"
  OnEventMove="DayPilotScheduler1_EventMove" 
/>

Example EventMove handler:

protected void DayPilotScheduler1_EventMove(object sender, DayPilot.Web.Ui.Events.EventMoveEventArgs e)
{
  // update the database
  // ...

  // reload events and refresh the scheduler on the client side
  DayPilotScheduler1.DataSource = LoadData();  // your method
  DayPilotScheduler1.DataBind();
  DayPilotScheduler1.UpdateWithMessage("Event moved.");
}

If any changes are made to the event data set (which is the typical case), it is necessary to redraw the event set on the client side using an Update() or UpdateWithMessage() call.

Asking for Confirmation

The server-side event handler will only be fired if the user confirms the action:

<DayPilot:DayPilotScheduler runat="server" id="DayPilotScheduler1"
  ...
  
  ClientObjectName="dps"
  EventMoveHandling = "JavaScript"
  EventMoveJavaScript="if (confirm('Do you really want to move this event?')) { dps.eventMoveCallBack(e, newStart, newEnd, newResource); } "
  OnEventMove="DayPilotScheduler1_EventMove" 
/>

ASP.NET MVC

Drag & drop event moving is disabled by default.

It can be enabled using EventMoveHandling property. It has to be set to one of the following values:

  • CallBack

  • Notify

  • JavaScript

CallBack event handling will fire a server-side event handler (OnEventMove) using an AJAX callback.

Notify event handling type will update the scheduler on the client immediately and then notify the server using an AJAX call. Notify is much faster than CallBack.

JavaScript event handling will fire the JavaScript code specified in EventMoveJavaScript.

  • The following variables are available to the client-side handler: e, newStart, newEnd, newResource, external, ctrl, shift (see DayPilot.Scheduler.onEventMove)

  • The client side handler can call the server-side handler using eventMoveCallBack() method

Server-Side Handler

@Html.DayPilotScheduler("dps", new DayPilotSchedulerConfig {
  BackendUrl = ResolveUrl("~/Scheduler/Backend"),
  ...
  EventMoveHandling = EventMoveHandlingType.CallBack
})

The EventMove event can be handled by overriding the OnEventMove method in the DayPilotScheduler implementing class:

protected override void OnEventMove(EventMoveArgs e)
{
  new EventManager(Controller).EventMove(e.Id, e.NewStart, e.NewEnd, e.NewResource);
  Update();
}

protected override void OnFinish()
{
  // only load the data if an update was requested by an Update() call
  if (UpdateType == CallBackUpdateType.None)
  {
    return;
  }

  Events = new EventManager(Controller).FilteredData(StartDate, EndDate, (string)ClientState["filter"]).AsEnumerable();

  DataStartField = "start";
  DataEndField = "end";
  DataTextField = "text";
  DataIdField = "id";
  DataResourceField = "resource";
}

If any changes are made to the event data set (which is the typical case), it is necessary to redraw the event set on the client side using an Update() call.