# scheduler-external-drag-and-drop

> Timeline scheduler that accepts dragging consultant appointments from an external tree-view list.

**Framework:** angular  **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/angular/scheduler-external-drag-and-drop.json
```

**Install Package(s)**

```bash
npm install @syncfusion/ej2-angular-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/external-drag-drop.component.ts

```typescript
import { Component, ViewEncapsulation, Inject, ViewChild } from '@angular/core';
import { hospitalData, waitingList } from '../data';
import { extend, closest, remove, addClass } from '@syncfusion/ej2-base';
import { EventSettingsModel, View, GroupModel, TimelineViewsService, TimelineMonthService, ResizeService, WorkHoursModel, DragAndDropService, ResourceDetails, ScheduleComponent, ActionEventArgs, CellClickEventArgs, ScheduleModule } from '@syncfusion/ej2-angular-schedule';
import { DragAndDropEventArgs } from '@syncfusion/ej2-navigations';
import { TreeViewComponent, TreeViewModule } from '@syncfusion/ej2-angular-navigations';
import { NgIf } from '@angular/common';
@Component({
    // tslint:disable-next-line:component-selector
    selector: 'control-content',
    templateUrl: 'external-drag-drop.html',
    styleUrls: ['external-drag-drop.style.css'],
    encapsulation: ViewEncapsulation.None,
    providers: [TimelineViewsService, TimelineMonthService, ResizeService, DragAndDropService],
    standalone: true,
    imports: [ScheduleModule, NgIf, TreeViewModule]
})
export class ExternalDragDropComponent {
  @ViewChild('scheduleObj') public scheduleObj!: ScheduleComponent;
  @ViewChild('treeObj') public treeObj!: TreeViewComponent;

  public isTreeItemDropped = false;
  public draggedItemId = '';
  public data: Record<string, any>[] = extend([], hospitalData as object[], undefined, true) as Record<string, any>[];
  public selectedDate: Date = new Date(2021, 7, 2);
  public currentView: View = 'TimelineDay';
  public workHours: WorkHoursModel = { start: '08:00', end: '18:00' };
  public departmentDataSource: Record<string, any>[] = [
    { Text: 'GENERAL', Id: 1, Color: '#bbdc00' },
    { Text: 'DENTAL', Id: 2, Color: '#9e5fff' }
  ];
  public consultantDataSource: 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' }
  ];
  public group: GroupModel = { enableCompactView: false, resources: ['Departments', 'Consultants'] };
  public allowMultiple = false;
  public eventSettings: EventSettingsModel = {
    dataSource: this.data,
    fields: {
      subject: { title: 'Patient Name', name: 'Name' },
      startTime: { title: 'From', name: 'StartTime' },
      endTime: { title: 'To', name: 'EndTime' },
      description: { title: 'Reason', name: 'Description' }
    }
  };

  public field: Record<string, any> = { dataSource: waitingList, id: 'Id', text: 'Name' };
  public allowDragAndDrop = true;

  public getConsultantName(value: ResourceDetails): string {
    return (value as ResourceDetails).resourceData[(value as ResourceDetails).resource.textField!] as string;
  }

  public getConsultantStatus(value: ResourceDetails): boolean {
    const resourceName: string = this.getConsultantName(value);
    return !(resourceName === 'GENERAL' || resourceName === 'DENTAL');
  }

  public getConsultantDesignation(value: ResourceDetails): string {
    const resourceName: string = this.getConsultantName(value);
    if (resourceName === 'GENERAL' || resourceName === 'DENTAL') {
      return '';
    } else {
      return (value as ResourceDetails).resourceData['Designation'] as string;
    }
  }

  public getConsultantImageName(value: ResourceDetails): string {
    return this.getConsultantName(value).toLowerCase();
  }

  public onTreeDrag(event: any): void {
    if (this.scheduleObj.isAdaptive) {
      const classElement: HTMLElement | null = this.scheduleObj.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');
      }
    }
  }

  public onActionBegin(event: ActionEventArgs): void {
    if (event.requestType === 'eventCreate' && this.isTreeItemDropped) {
      const treeViewData: Record<string, any>[] = this.treeObj.fields.dataSource as Record<string, any>[];
      const draggedItemIdNum: number = parseInt(this.draggedItemId, 10);
      const filteredPeople: Record<string, any>[] = treeViewData.filter((item: any) => item['Id'] !== draggedItemIdNum);
      this.treeObj.fields.dataSource = filteredPeople;
      const elements: NodeListOf<HTMLElement> = document.querySelectorAll('.e-drag-item.treeview-external-drag');
      for (const element of [].slice.call(elements)) {
        remove(element);
      }
    }
  }

  public onItemSelecting(args: any): void {
    args.cancel = true;
  }

  public onTreeDragStop(event: DragAndDropEventArgs): void {
    const treeElement: Element = closest(event.target, '.e-treeview') as Element;
    const classElement: HTMLElement | null = this.scheduleObj.element.querySelector('.e-device-hover');
    if (classElement) {
      classElement.classList.remove('e-device-hover');
    }
    if (!treeElement) {
      event.cancel = true;
      const scheduleElement: Element = closest(event.target, '.e-content-wrap') as Element;
      if (scheduleElement) {
        const treeviewData: Record<string, any>[] = this.treeObj.fields.dataSource as Record<string, any>[];
        if (event.target.classList.contains('e-work-cells')) {
          const draggedId: number = parseInt(event.draggedNodeData['id'] as string, 10);
          const filteredData: Record<string, any>[] = treeviewData.filter((item: any) =>
            item.Id === draggedId);
          const cellData: CellClickEventArgs = this.scheduleObj.getCellDetails(event.target);
          const resourceDetails: ResourceDetails = this.scheduleObj.getResourcesByIndex(cellData.groupIndex!);
          const 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']
          };
          this.scheduleObj.openEditor(eventData, 'Add', true);
          this.isTreeItemDropped = true;
          this.draggedItemId = event.draggedNodeData['id'] as string;
        }
      }
    }
    document.body.classList.remove('e-disble-not-allowed');
  }
  public onTreeDragStart() {
    document.body.classList.add('e-disble-not-allowed');
  }

}

```

### src/components/scheduler-external-drag-and-drop/external-drag-drop.html

```html
<div class="control-section">
  <div class="drag-sample-wrapper">
    <div class="schedule-container">
      <div class="title-container">
        <div class="title-text">Doctor's Appointments</div>
      </div>
      <ejs-schedule #scheduleObj cssClass='schedule-drag-drop' width='100%' height='650px' [group]="group"
        [currentView]="currentView" [selectedDate]="selectedDate" [workHours]="workHours"
        [eventSettings]="eventSettings" (actionBegin)="onActionBegin($event)">
        <e-resources>
          <e-resource field='DepartmentID' title='Department' name='Departments' [dataSource]='departmentDataSource'
            textField='Text' idField='Id' colorField='Color'>
          </e-resource>
          <e-resource field='ConsultantID' title='Consultant' name='Consultants' [dataSource]='consultantDataSource'
            [allowMultiple]='allowMultiple' textField='Text' idField='Id' groupIDField="GroupId" colorField='Color'>
          </e-resource>
        </e-resources>
        <ng-template #resourceHeaderTemplate let-data>
          <div class="template-wrap">
            <div class="specialist-category">
              <div *ngIf="getConsultantStatus(data)">
                <img src="./assets/schedule/images/{{getConsultantImageName(data)}}.png" alt="{{getConsultantImageName(data)}}" class="specialist-image" />
              </div>
              <div class="specialist-name">{{getConsultantName(data)}}</div>
              <div class="specialist-designation">{{getConsultantDesignation(data)}}</div>
            </div>
          </div>
        </ng-template>
        <e-views>
          <e-view option='TimelineDay'></e-view>
          <e-view option='TimelineMonth'></e-view>
        </e-views>
      </ejs-schedule>
    </div>
    <div class="treeview-container">
      <div class="title-container">
        <div class="title-text">Waiting List</div>
      </div>
      <ejs-treeview #treeObj [fields]='field' cssClass='treeview-external-drag' dragArea=".drag-sample-wrapper"
        [allowDragAndDrop]='allowDragAndDrop' (nodeDragStop)="onTreeDragStop($event)" (nodeDragStart)="onTreeDragStart()"
        (nodeDragging)="onTreeDrag($event)" (nodeSelecting)="onItemSelecting($event)">
        <ng-template #nodeTemplate let-data>
          <div id="waiting">
            <div id="waitdetails">
              <div id="waitlist">{{data.Name}}</div>
              <div id="waitcategory">{{data.DepartmentName}} - {{data.Description}}</div>
            </div>
          </div>
        </ng-template>
      </ejs-treeview>
    </div>
  </div>
</div>

```

### src/components/scheduler-external-drag-and-drop/external-drag-drop.style.css

```css
.drag-sample-wrapper {
  display: -ms-flexbox;
  display: flex;
}

.schedule-container {
  padding-right: 10px;
  width: 100%;
}

.title-container {
  padding-bottom: 10px;
}

.e-schedule.schedule-drag-drop .e-resource-cells.e-parent-node .template-wrap {
  padding: 3px 0px;
}

.title-text {
  font-size: 18px;
  margin: 0px;
  font-weight: bold;
  text-align: center;
  line-height: 1.1;
}

.treeview-external-drag #waiting {
  height: 100%;
  padding: 0;
}

.treeview-external-drag #waitdetails {
  width: 95%;
  float: left;
  height: 100%;
  padding: 0;
}

.treeview-external-drag #waitlist {
  width: 100%;
  height: 50%;
  font-weight: bold;
  font-family: "Segoe UI";
  font-size: 12px;
  padding: 5px 0 0 10px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.treeview-external-drag #waitcategory {
  height: 50%;
  font-family: "Segoe UI";
  font-size: 10px;
  opacity: 0.6;
  padding-left: 10px;
  padding-top: 5px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.treeview-external-drag .e-list-text, .treeview-external-drag.e-rtl .e-list-text, .e-bigger .treeview-external-drag .e-list-text, .e-bigger .treeview-external-drag.e-rtl .e-list-text {
  border: 0.5px solid #E1E7EC;
  height: 50px;
  line-height: 15px !important;
  padding: 0 5px;
  width: 220px;
}

.treeview-external-drag .e-list-parent, .treeview-external-drag.e-rtl .e-list-parent, .e-bigger .treeview-external-drag .e-list-parent, .e-bigger .treeview-external-drag.e-rtl .e-list-parent {
  height: 100%;
  padding: 0 2px;
}

.treeview-external-drag .e-list-item, .e-bigger .treeview-external-drag .e-list-item {
  height: 100%;
  padding: 0 0 5px 0;
}

.treeview-external-drag .e-fullrow, .e-bigger .treeview-external-drag .e-fullrow {
  height: 55px;
}

.treeview-external-drag .e-list-item.e-hover>.e-fullrow, .treeview-external-drag .e-list-item.e-active>.e-fullrow, .treeview-external-drag .e-list-item.e-active.e-hover>.e-fullrow, .e-bigger .treeview-external-drag .e-list-item.e-hover>.e-fullrow, .e-bigger .treeview-external-drag .e-list-item.e-active>.e-fullrow, .e-bigger .treeview-external-drag .e-list-item.e-active.e-hover>.e-fullrow {
  background-color: transparent;
  border-color: transparent;
  box-shadow: none !important;
}

.fluent2-highcontrast .treeview-external-drag .e-list-item.e-hover > .e-text-content .e-list-text {
  color: #fff;
}

.treeview-external-drag .e-text-content, .e-bigger .treeview-external-drag .e-text-content, .treeview-external-drag.e-rtl .e-text-content, .e-bigger .treeview-external-drag.e-rtl .e-text-content {
  padding: 0;
  background-color: inherit;
}

.e-drag-item.e-treeview.treeview-external-drag, .e-bigger .e-drag-item.e-treeview.treeview-external-drag {
  padding: 0 !important;
}

.e-schedule.schedule-drag-drop .e-timeline-view .e-resource-left-td, .e-schedule.schedule-drag-drop .e-timeline-month-view .e-resource-left-td {
  width: 160px;
}

.e-schedule.schedule-drag-drop .e-resource-cells.e-parent-node .specialist-category {
  padding-left: 30px
}

.e-schedule.e-rtl.schedule-drag-drop .e-resource-cells.e-parent-node .specialist-category {
  padding-right: 30px
}

.e-schedule.schedule-drag-drop .e-resource-cells.e-child-node .specialist-category, .e-schedule.schedule-drag-drop .e-resource-cells.e-child-node .specialist-name {
  padding: 5px
}

.e-schedule.schedule-drag-drop .e-resource-cells.e-parent-node .specialist-name {
  padding: 0 10px
}

.e-schedule.schedule-drag-drop .specialist-name {
  font-size: 13px;
}

.e-schedule.schedule-drag-drop .specialist-designation {
  font-size: 10px;
}

.e-device-hover {
  background-color: #e0e0e0 !important;
}

.e-schedule.schedule-drag-drop .specialist-image {
  width: 40px;
  height: 40px;
  float: left;
  border-radius: 50%;
  margin-right: 10px;
}

@media (max-width: 550px) {
  /* custom code start*/
  .drag-sample-wrapper {
    display: block;
  }
  .schedule-container {
    padding-bottom: 10px
  }
  /* custom code end*/
  .treeview-external-drag.e-treeview, .e-bigger .treeview-external-drag.e-treeview {
    width: 250px;
  }
  .e-bigger .treeview-external-drag.e-treeview.e-drag-item {
    position: relative !important;
  }
}
.e-disble-not-allowed {
  cursor: unset !important;
}

.e-drag-item.treeview-external-drag .e-icon-expandable {
  display: none;
}
```
