# scheduler-external-drag-and-drop

> Scheduler accepts drag-and-drop from an external tree view into its time slots.

**Framework:** react  **Component:** Scheduler  **Variant:** external-drag-and-drop

## Get this item

**If you are an agent, fetch the JSON.** Source is inlined, so one request is enough and no tooling is required:

```
GET https://ai.syncfusion.com/r/react/ts/scheduler-external-drag-and-drop.json
```

**Install Package(s)**

```bash
npm install @syncfusion/ej2-navigations @syncfusion/ej2-react-navigations @syncfusion/ej2-react-schedule
```

**Notes**

- Syncfusion release: 2026 Volume 2 (v34.1.29)
- The Syncfusion package is licensed. The composition in this file is source you own and edit. See https://ai.syncfusion.com/licensing.md

## Source files

### src/components/scheduler-external-drag-and-drop/Scheduler.tsx

```tsx
import { useRef } from 'react';
import { ScheduleComponent, type TreeViewArgs, ResourcesDirective, ResourceDirective, ViewsDirective, ViewDirective, type ResourceDetails, Inject, TimelineViews, Resize, DragAndDrop, TimelineMonth, type ActionEventArgs, type CellClickEventArgs } from '@syncfusion/ej2-react-schedule';
import { extend, closest, remove, addClass } from '@syncfusion/ej2-base';
import { type DragAndDropEventArgs } from '@syncfusion/ej2-navigations';
import { TreeViewComponent } from '@syncfusion/ej2-react-navigations';

/**
 * schedule resources group-editing sample
 */

let waitingList = [
  { "Id": 1, "Name": "Steven", "StartTime": "2021-09-04T02:00:00.000Z", "EndTime": "2021-09-04T04:00:00.000Z", "Description": "Consulting", "DepartmentName": "GENERAL" },
  { "Id": 2, "Name": "Milan", "StartTime": "2021-09-05T03:00:00.000Z", "EndTime": "2021-09-05T05:00:00.000Z", "Description": "Bad Breath", "DepartmentName": "DENTAL" },
  { "Id": 3, "Name": "Laura", "StartTime": "2021-09-05T04:00:00.000Z", "EndTime": "2021-09-05T05:00:00.000Z", "Description": "Eye Checkup", "DepartmentName": "GENERAL" },
  { "Id": 4, "Name": "Janet", "StartTime": "2021-09-04T05:30:00.000Z", "EndTime": "2021-09-04T07:00:00.000Z", "Description": "Gum Disease", "DepartmentName": "DENTAL" },
  { "Id": 5, "Name": "Adams", "StartTime": "2021-09-04T05:30:00.000Z", "EndTime": "2021-09-04T07:00:00.000Z", "Description": "Observation", "DepartmentName": "GENERAL" },
  { "Id": 6, "Name": "John", "StartTime": "2021-09-04T05:30:00.000Z", "EndTime": "2021-09-04T07:00:00.000Z", "Description": "Mouth Sores", "DepartmentName": "DENTAL" }
];

let hospitalData = [
  { "Id": 10, "Name": "David", "StartTime": "2021-08-02T03:30:00.000Z", "EndTime": "2021-08-02T04:30:00.000Z", "Description": "Health Checkup", "DepartmentID": 1, "ConsultantID": 1, "DepartmentName": "GENERAL" },
  { "Id": 11, "Name": "John", "StartTime": "2021-08-02T05:00:00.000Z", "EndTime": "2021-08-02T06:00:00.000Z", "Description": "Tooth Erosion", "DepartmentID": 2, "ConsultantID": 2, "DepartmentName": "DENTAL" },
  { "Id": 12, "Name": "Peter", "StartTime": "2021-08-02T06:30:00.000Z", "EndTime": "2021-08-02T07:30:00.000Z", "Description": "Eye and Spectacles Checkup", "DepartmentID": 1, "ConsultantID": 3, "DepartmentName": "GENERAL" },
  { "Id": 13, "Name": "Starc", "StartTime": "2021-08-02T08:30:00.000Z", "EndTime": "2021-08-02T09:30:00.000Z", "Description": "Toothaches", "DepartmentID": 2, "ConsultantID": 4, "DepartmentName": "DENTAL" },
  { "Id": 14, "Name": "James", "StartTime": "2021-08-02T04:30:00.000Z", "EndTime": "2021-08-02T05:30:00.000Z", "Description": "Surgery Appointment", "DepartmentID": 1, "ConsultantID": 5, "DepartmentName": "GENERAL" },
  { "Id": 15, "Name": "Jercy", "StartTime": "2021-08-02T04:00:00.000Z", "EndTime": "2021-08-02T05:00:00.000Z", "Description": "Tooth Sensitivity", "DepartmentID": 2, "ConsultantID": 6, "DepartmentName": "DENTAL" },
  { "Id": 16, "Name": "Albert", "StartTime": "2021-08-03T04:30:00.000Z", "EndTime": "2021-08-03T06:00:00.000Z", "Description": "Skin care treatment", "DepartmentID": 1, "ConsultantID": 7, "DepartmentName": "GENERAL" },
  { "Id": 17, "Name": "Louis", "StartTime": "2021-08-03T07:00:00.000Z", "EndTime": "2021-08-03T08:15:00.000Z", "Description": "General Checkup", "DepartmentID": 1, "ConsultantID": 9, "DepartmentName": "GENERAL" },
  { "Id": 18, "Name": "Williams", "StartTime": "2021-08-03T06:30:00.000Z", "EndTime": "2021-08-03T08:30:00.000Z", "Description": "Mouth Sores", "DepartmentID": 2, "ConsultantID": 10, "DepartmentName": "DENTAL" },
  { "Id": 19, "Name": "David", "StartTime": "2021-08-03T11:00:00.000Z", "EndTime": "2021-08-03T12:45:00.000Z", "Description": "Eye checkup and Treatment", "DepartmentID": 1, "ConsultantID": 1, "DepartmentName": "GENERAL" },
  { "Id": 20, "Name": "John", "StartTime": "2021-08-03T14:00:00.000Z", "EndTime": "2021-08-03T16:15:00.000Z", "Description": "Toothaches", "DepartmentID": 2, "ConsultantID": 2, "DepartmentName": "DENTAL" }
];

const ExternalDragDrop = () => {
  let scheduleObj = useRef<ScheduleComponent>(null);
  let treeObj = useRef<TreeViewComponent>(null);
  let isTreeItemDropped: boolean = false;
  let draggedItemId: string = '';
  const allowDragAndDrops: boolean = true;
  const fields: Record<string, any> = { dataSource: waitingList, id: 'Id', text: 'Name' };
  const data: Record<string, any>[] = extend([], hospitalData, null, true) as Record<string, any>[];
  const departmentData: Record<string, any>[] = [
    { Text: 'GENERAL', Id: 1, Color: '#bbdc00' },
    { Text: 'DENTAL', Id: 2, Color: '#9e5fff' }
  ];
  const consultantData: Record<string, any>[] = [
    { Text: 'Alice', Id: 1, GroupId: 1, Color: '#bbdc00', Designation: 'Cardiologist' },
    { Text: 'Nancy', Id: 2, GroupId: 2, Color: '#9e5fff', Designation: 'Orthodontist' },
    { Text: 'Robert', Id: 3, GroupId: 1, Color: '#bbdc00', Designation: 'Optometrist' },
    { Text: 'Robson', Id: 4, GroupId: 2, Color: '#9e5fff', Designation: 'Periodontist' },
    { Text: 'Laura', Id: 5, GroupId: 1, Color: '#bbdc00', Designation: 'Orthopedic' },
    { Text: 'Margaret', Id: 6, GroupId: 2, Color: '#9e5fff', Designation: 'Endodontist' }
  ];

  const getConsultantName = (value: ResourceDetails | TreeViewArgs): string => {
    return (value as ResourceDetails).resourceData[(value as ResourceDetails).resource.textField] as string;
  }

  const getConsultantImage = (value: ResourceDetails): string => {
    return getConsultantName(value).toLowerCase();
  }

  const getConsultantDesignation = (value: ResourceDetails): string => {
    return (value as ResourceDetails).resourceData.Designation as string;
  }

  const resourceHeaderTemplate = (props: any)  => {
    return (
      <div className="template-wrap">
        <div className="specialist-category">
          <div className={"specialist-image " + getConsultantImage(props)}></div>
          <div className="specialist-name"> {getConsultantName(props)}</div>
          <div className="specialist-designation">{getConsultantDesignation(props)}</div>
        </div>
      </div>
    );
  }

  const treeTemplate = (props: any) => {
    return (
      <div id="waiting">
        <div id="waitdetails">
          <div id="waitlist">{props.Name}</div>
          <div id="waitcategory">{props.DepartmentName} - {props.Description}</div>
        </div>
      </div>
    );
  }

  const onItemSelecting = (args: any): void => {
    args.cancel = true;
  }

  const onTreeDrag = (event: any): void => {
    if (scheduleObj.current.isAdaptive) {
      let classElement: HTMLElement = scheduleObj.current.element.querySelector('.e-device-hover');
      if (classElement) {
        classElement.classList.remove('e-device-hover');
      }
      if (event.target.classList.contains('e-work-cells')) {
        addClass([event.target], 'e-device-hover');
      }
    }
  }

  const onActionBegin = (event: ActionEventArgs): void => {
    if (event.requestType === 'eventCreate' && isTreeItemDropped) {
      let treeViewData: Record<string, any>[] = treeObj.current.fields.dataSource as Record<string, any>[];
      const filteredPeople: Record<string, any>[] = treeViewData.filter((item: any) => item.Id !== parseInt(draggedItemId, 10));
      treeObj.current.fields.dataSource = filteredPeople;
      let elements: NodeListOf<HTMLElement> = document.querySelectorAll('.e-drag-item.treeview-external-drag');
      for (let i: number = 0; i < elements.length; i++) {
        remove(elements[i]);
      }
    }
  }

  const onTreeDragStop = (event: DragAndDropEventArgs): void => {
    let treeElement: Element = closest(event.target, '.e-treeview');
    let classElement: HTMLElement = scheduleObj.current.element.querySelector('.e-device-hover');
    if (classElement) {
      classElement.classList.remove('e-device-hover');
    }
    if (!treeElement) {
      event.cancel = true;
      let scheduleElement: Element = closest(event.target, '.e-content-wrap');
      if (scheduleElement) {
        let treeviewData: Record<string, any>[] = treeObj.current.fields.dataSource as Record<string, any>[];
        if (event.target.classList.contains('e-work-cells')) {
          const filteredData: Record<string, any>[] = treeviewData.filter((item: any) => item.Id === parseInt(event.draggedNodeData.id as string, 10));
          let cellData: CellClickEventArgs = scheduleObj.current.getCellDetails(event.target);
          let resourceDetails: ResourceDetails = scheduleObj.current.getResourcesByIndex(cellData.groupIndex);
          let eventData: Record<string, any> = {
            Name: filteredData[0].Name,
            StartTime: cellData.startTime,
            EndTime: cellData.endTime,
            IsAllDay: cellData.isAllDay,
            Description: filteredData[0].Description,
            DepartmentID: resourceDetails.resourceData.GroupId,
            ConsultantID: resourceDetails.resourceData.Id
          };
          scheduleObj.current.openEditor(eventData, 'Add', true);
          isTreeItemDropped = true;
          draggedItemId = event.draggedNodeData.id as string;
        }
      }
    }
    document.body.classList.remove('e-disble-not-allowed');
  }

  const onTreeDragStart = () => {
    document.body.classList.add('e-disble-not-allowed');
  }

  return (
    <div className='schedule-control-section'>
      <div className='col-lg-12 control-section'>
        <div className='control-wrapper drag-sample-wrapper'>
          <div className="schedule-container">
            <div className="title-container">
              <h1 className="title-text">Doctor's Appointments</h1>
            </div>
            <ScheduleComponent ref={scheduleObj} cssClass='schedule-drag-drop' width='100%' height='650px' selectedDate={new Date(2021, 7, 2)} currentView='TimelineDay' resourceHeaderTemplate={resourceHeaderTemplate} eventSettings={{ dataSource: data, fields: { subject: { title: 'Patient Name', name: 'Name' }, startTime: { title: "From", name: "StartTime" }, endTime: { title: "To", name: "EndTime" }, description: { title: 'Reason', name: 'Description' } } }} group={{ enableCompactView: false, resources: ['Departments', 'Consultants'] }} actionBegin={onActionBegin} >
              <ResourcesDirective>
                <ResourceDirective field='DepartmentID' title='Department' name='Departments' allowMultiple={false} dataSource={departmentData} textField='Text' idField='Id' colorField='Color' />
                <ResourceDirective field='ConsultantID' title='Consultant' name='Consultants' allowMultiple={false} dataSource={consultantData} textField='Text' idField='Id' groupIDField="GroupId" colorField='Color' />
              </ResourcesDirective>
              <ViewsDirective>
                <ViewDirective option='TimelineDay' />
                <ViewDirective option='TimelineMonth' />
              </ViewsDirective>
              <Inject services={[TimelineViews, TimelineMonth, Resize, DragAndDrop]} />
            </ScheduleComponent>
          </div>
          <div className="treeview-container">
            <div className="title-container">
              <h1 className="title-text">Waiting List</h1>
            </div>
            <TreeViewComponent ref={treeObj} cssClass='treeview-external-drag' dragArea=".drag-sample-wrapper" nodeTemplate={treeTemplate} fields={fields} nodeDragStop={onTreeDragStop} nodeSelecting={onItemSelecting} nodeDragging={onTreeDrag} nodeDragStart={onTreeDragStart} allowDragAndDrop={allowDragAndDrops} />
          </div>
        </div>
      </div>
    </div>
  );
}
export default ExternalDragDrop;
```
