Row drag and drop in Angular Gantt component

18 Oct 202524 minutes to read

The Syncfusion® Angular Gantt chart component includes built-in support for row drag and drop, enabling rows to be rearranged within the Gantt chart or dropped into custom components.

To enable this feature, inject the RowDDService in the providers array of the AppComponent. Once injected, enable the functionality by setting the allowRowDragAndDrop property.

Drag and drop within the Gantt chart

The Gantt component allows you to rearrange rows using a drag icon. To enable this feature, set the allowRowDragAndDrop property to true.

import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttModule, RowDDService, EditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule],
  providers: [RowDDService, EditService, SelectionService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <ejs-gantt height="450px" [treeColumnIndex]="1" [dataSource]="data" [splitterSettings]="splitterSettings" [allowRowDragAndDrop]="true" [taskFields]="taskSettings">
      <e-columns>
        <e-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-column>
        <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
        <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
        <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
        <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
      </e-columns>
    </ejs-gantt>`
})

export class AppComponent implements OnInit {
  public data: object[] = [];
  public taskSettings!: object;
  public splitterSettings!:object;

  ngOnInit(): void {
    this.data = GanttData;

    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      dependency: 'Predecessor',
      child: 'subtasks'
    };

    this.splitterSettings = {
      position: '75%'
    };
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Different drop positions

In a Gantt chart, drag and drop functionality allows rearranging rows to adjust their position. You can drop rows in the following positions:

  1. Above
  2. Below
  3. Child

Above

If the border line appears at the top of the target row (e.g., Task ID: 6) while dropping, the row will be placed above the target row as a sibling.

Above Position

Below

If the border line appears at the bottom of the target row (e.g., Task ID: 6) while dropping, the row will be placed below the target row as a sibling.

Below Position

Child

If the border line appears at both the top and bottom of the target row (e.g., Task ID: 6) while dropping, the row will be added as a child to the target row.

Child Position

Drag and drop to custom component

You can drag rows from the Gantt component into custom components for seamless data transfer. To enable this feature, set the allowRowDragAndDrop property to true, and configure the targetID property within the rowDropSettings object of the treeGrid in the Gantt instance, inside the load event. The value of targetID must match the ID of the destination component. You can use the rowDrop event to handle the drop and perform necessary actions.

import { Component, ViewEncapsulation, ViewChild, OnInit } from '@angular/core';
import { GanttModule, GanttComponent, RowDDService as GanttRowDDService, EditService as GanttEditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { TreeGridModule, TreeGridComponent, RowDDService, EditService, RowDragEventArgs } from '@syncfusion/ej2-angular-treegrid';
import { isNullOrUndefined } from '@syncfusion/ej2-base';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule, TreeGridModule],
  providers: [GanttRowDDService, RowDDService, SelectionService, EditService, GanttEditService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <div class="container">
      <div class="gantt-panel">
        <ejs-gantt #gantt id="ganttDefault" height="450px" [treeColumnIndex]="1" [dataSource]="data" [allowRowDragAndDrop]="true" [taskFields]="taskSettings" [selectionSettings]="selectionOptions" [editSettings]="editSettings" [splitterSettings]="splitterSettings" (load)="load()" (rowDrop)="onRowDrop($event)">
          <e-columns>
            <e-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-column>
            <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
            <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
            <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
            <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
          </e-columns>
        </ejs-gantt>
      </div>
      <div class="treegrid-panel">
        <ejs-treegrid #treegrid id="TreeGrid" [editSettings]="treeGridEditSettings" childMapping="subtasks">
          <e-columns>
            <e-column field="taskID" headerText="Task ID" [isPrimaryKey]="true" textAlign="Right" width="90"></e-column>
            <e-column field="taskName" headerText="Task Name" textAlign="Left" width="180"></e-column>
            <e-column field="startDate" headerText="Start Date" textAlign="Right" format="yMd" width="120"></e-column>
            <e-column field="duration" headerText="Duration" textAlign="Right" width="120"></e-column>
          </e-columns>
        </ejs-treegrid>
      </div>
    </div>`,
  styles: [`
    .container {
      display: flex;
      gap: 2%;
    }
    .gantt-panel, .treegrid-panel {
      width: 49%;
    }
  `]
})

export class AppComponent implements OnInit {
  @ViewChild('gantt') public ganttInstance?: GanttComponent;
  @ViewChild('treegrid') public treeGridObject?: TreeGridComponent;
  public data: object[] = [];
  public taskSettings: object = { };
  public treeGridEditSettings: object = { };
  public selectionOptions: object = { };
  public editSettings: object = { };
  public splitterSettings: object = { };

  ngOnInit(): void {
    this.data = GanttData;
    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      dependency: 'Predecessor',
      child: 'subtasks'
    };
    this.selectionOptions = { type: 'Multiple' };
    this.treeGridEditSettings = { allowAdding: true, allowEditing: true };
    this.editSettings = { allowDeleting: true };
    this.splitterSettings = { position: '75%' };
  }

  public load(): void {
    (this.ganttInstance as GanttComponent).treeGrid.rowDropSettings = { targetID: 'TreeGrid' };
  }

  public onRowDrop(args: RowDragEventArgs): void {
    const targetGrid = (args.target as Element).closest('.e-grid');
    if (targetGrid) {
      args.cancel = true;
      const rowIndex = !isNullOrUndefined((args.target as Element).closest('.e-row'))
        ? ((args.target as HTMLElement).closest('.e-row') as any).rowIndex
        : 0;
      const draggedData = args.data as object[];
      draggedData.forEach(item => {
        this.treeGridObject?.addRecord(item, rowIndex);
        this.ganttInstance?.deleteRecord(item);
      });
    }
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Drag and drop multiple rows together

You can drag and drop multiple rows simultaneously in the Gantt component. To enable this functionality, set the selectionSettings.type property to Multiple , and set the allowRowDragAndDrop property is set to true.

import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttModule, RowDDService, EditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule],
  providers: [RowDDService, SelectionService, EditService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <ejs-gantt id="ganttDefault" height="450px" [dataSource]="data" [treeColumnIndex]="1" [allowRowDragAndDrop]="true" [taskFields]="taskSettings" [selectionSettings]="selectionSettings" [splitterSettings]="splitterSettings">
      <e-columns>
        <e-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-column>
        <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
        <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
        <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
        <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
      </e-columns>
    </ejs-gantt>`
})

export class AppComponent implements OnInit {
  public data: object[] = [];
  public taskSettings!: object;
  public selectionSettings!: object;
  public splitterSettings!: object;

  ngOnInit(): void {
    this.data = GanttData;

    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      dependency: 'Predecessor',
      child: 'subtasks'
    };
    this.selectionSettings = {
      type: 'Multiple'
    };
    this.splitterSettings = {
      position: '75%'
    };
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Taskbar drag and drop between rows

You can rearrange rows in the Gantt component by dragging the taskbar element. This functionality is enabled by setting the allowTaskbarDragAndDrop property to true, allowing taskbars to be repositioned across rows for improved scheduling control.

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { GanttModule, RowDDService, EditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule],
  providers: [RowDDService, SelectionService, EditService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <ejs-gantt height="450px" [dataSource]="data" [treeColumnIndex]="1" [splitterSettings]="splitterSettings" [allowRowDragAndDrop]="true" [allowTaskbarDragAndDrop]="true" [editSettings]="editSettings" [taskFields]="taskSettings">
      <e-columns>
        <e-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-column>
        <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
        <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
        <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
        <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
      </e-columns>
    </ejs-gantt>`
})

export class AppComponent implements OnInit {
  public data: object[] = [];
  public taskSettings: object = {};
  public splitterSettings: object = {};
  public editSettings: object = {};

  ngOnInit(): void {
    this.data = GanttData;
    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      child: 'subtasks'
    };
    this.splitterSettings = {
      position: '50%'
    };
    this.editSettings = {
      allowTaskbarEditing: true
    };
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Drag and drop interactions with server side

You can perform row drag and drop operations in the Gantt component with server-side interaction.

To handle drag and drop on the server side, use the rowDrop event on the client side. This event must be captured and processed to retrieve the necessary information about the dragged record and its intended new position. On the server, the record should be removed from its original index and inserted at the appropriate location based on the event data.

Follow these steps to implement server-side drag and drop:

Step 1: Add the following code to the app.component.ts file to handle the rowDrop event:

import { Component, ViewChild } from '@angular/core';
import { GanttComponent, ToolbarItem, EditSettingsModel, } from '@syncfusion/ej2-angular-gantt';
import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
import { Ajax } from '@syncfusion/ej2-base';
import { RowDragEventArgs } from '@syncfusion/ej2-angular-grids';


@Component({
  selector: 'app-root',
  template: `
    <ejs-gantt #gantt [dataSource]='data' [treeColumnIndex]='1' (rowDrop)="rowDrop($event)" 
    [taskFields]="taskSettings" [splitterSettings] = "splitterSettings" [allowRowDragAndDrop]=true [editSettings]="editSettings" [toolbar]="toolbar" height="450">
        <e-columns>
            <e-column field='TaskID' headerText='Task ID' [isPrimaryKey]='true' width='150'></e-column>
            <e-column field='TaskName' headerText='Task Name' width='150'></e-column>
            <e-column field='Duration' headerText='Duration' width='150' textAlign='Right'></e-column>
        </e-columns>
    </ejs-gantt>`
})
export class AppComponent {
  @ViewChild('gantt') public ganttInstance?: GanttComponent
  public data?: DataManager;
  public editSettings?: EditSettingsModel;
  public toolbar?: ToolbarItem[];
  public taskSettings?: object;
  public splitterSettings?: object;

  ngOnInit(): void {
    this.data = new DataManager({
      url: '/Home/UrlDatasource',
      adaptor: new UrlAdaptor(),
      offline: true
    });
    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      child: 'subtasks',
      parentID: 'ParentId',
    };
    this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, };
    this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search'];
    this.splitterSettings = {
      position: '75%'
    };
  }

  public rowDrop(args: RowDragEventArgs) {
    const dragId = args.data[0][(this.ganttInstance as GanttComponent).taskFields.id];
    const dropId = args.dropRecord[(this.ganttInstance as GanttComponent).taskFields.id];
    var data = args.data[0];
    var positions = { dragidMapping: dragId, dropidMapping: dropId, position: args.dropPosition };
    const ajax = new Ajax({
      url: '/Home/DragandDrop',
      type: 'POST',
      dataType: "json",
      contentType: 'application/json; charset=utf-8',
      data: JSON.stringify({ value: data, pos: positions })
    });
    (this.ganttInstance as GanttComponent).showSpinner();
    ajax.send();
    ajax.onSuccess = (data: string) => {
      (this.ganttInstance as GanttComponent).hideSpinner();
    };
  }
}

Step 2: Implement server-side logic to process the drag and drop operation.

        public ActionResult UrlDatasource([FromBody] DataManagerRequest dm)
        {
            IEnumerable DataSource = GanttItems.GetSelfData();
            DataOperations operation = new DataOperations();

            if (dm.Sorted != null && dm.Sorted.Count > 0)
            {
                DataSource = operation.PerformSorting(DataSource, dm.Sorted);
            }
            if (dm.Where != null && dm.Where.Count > 0)
            {
                DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);
            }
            int count = DataSource.Cast<GanttItems>().Count();
            if (dm.Take != 0)
            {
                DataSource = operation.PerformTake(DataSource, dm.Take);
            }
             return dm.RequiresCounts ? Ok(new { result = DataSource, count }) : Ok(DataSource);

        }
          
        //Here handle the code of row drag and drop operations.
        public bool DragandDrop([FromBody] ICRUDModel value)
        {
            if (value.pos.position == "bottomSegment" || value.pos.position == "topSegment")
            {
                //for bottom and top segment drop position. If the dragged record is the only child for a particular record.
                //we need to set parentItem of dragged record to null and isParent of dragged record's parent to false.
                if (value.value.ParentId != null) // if dragged record has parent.
                {
                    var childCount = 0;
                    int parent = (int)value.value.ParentId;
                    childCount += FindChildRecords(parent); // finding the number of child for dragged record's parent.
                    if (childCount == 1) // if the dragged record is the only child for a particular record,
                    {
                        var i = 0;
                        for (; i < GanttItems.GetSelfData().Count; i++)
                        {
                            if (GanttItems.GetSelfData()[i].TaskID == parent)
                            {
                                //set isParent of dragged record's parent to false. 
                                GanttItems.GetSelfData()[i].isParent = false;
                                break;
                            }
                            if (GanttItems.GetSelfData()[i].TaskID == value.value.TaskID)
                            {
                                //set parentItem of dragged record to null.
                                GanttItems.GetSelfData()[i].ParentId = null;
                                break;
                            }


                        }
                    }
                }
                GanttItems.GetSelfData().Remove(GanttItems.GetSelfData().Where(ds => ds.TaskID == value.pos.dragidMapping).FirstOrDefault());
                var j = 0;
                for (; j < GanttItems.GetSelfData().Count; j++)
                {
                    if (GanttItems.GetSelfData()[j].TaskID == value.pos.dropidMapping)
                    {
                        //set dragged records parentItem with parentItem of.
                        //record in dropindex.
                        value.value.ParentId = GanttItems.GetSelfData()[j].ParentId;
                        break;
                    }
                }
                if (value.pos.position == "bottomSegment")
                {
                    this.Insert(value, value.pos.dropidMapping);
                }
                else if (value.pos.position == "topSegment")
                {
                    this.InsertAtTop(value, value.pos.dropidMapping);
                }
            }
            else if (value.pos.position == "middleSegment")
            {
                GanttItems.GetSelfData().Remove(GanttItems.GetSelfData().Where(ds => ds.TaskID == value.pos.dragidMapping).FirstOrDefault());
                value.value.ParentId = value.pos.dropidMapping;
                FindDropdata(value.pos.dropidMapping);
                this.Insert(value, value.pos.dropidMapping);
            }
            return true;
        }

        public ActionResult Insert([FromBody] ICRUDModel value, int rowIndex)
        {
            var i = 0;
            if (value.Action == "insert")
            {
                rowIndex = value.relationalKey;
            }
            Random ran = new Random();
            int a = ran.Next(100, 1000);

            for (; i < GanttItems.GetSelfData().Count; i++)
            {
                if (GanttItems.GetSelfData()[i].TaskID == rowIndex)
                {
                    value.value.ParentId = rowIndex;
                    if (GanttItems.GetSelfData()[i].isParent == false)
                    {
                        GanttItems.GetSelfData()[i].isParent = true;
                    }
                    break;

                }
            }
            i += FindChildRecords(rowIndex);
            GanttItems.GetSelfData().Insert(i, value.value);

            return Json(value.value);
        }

        public void InsertAtTop([FromBody] ICRUDModel value, int rowIndex)
        {
            var i = 0;
            for (; i < GanttItems.GetSelfData().Count; i++)
            {
                if (GanttItems.GetSelfData()[i].TaskID == rowIndex)
                {
                    break;

                }
            }
            i += FindChildRecords(rowIndex);
            GanttItems.GetSelfData().Insert(i - 1, value.value);
        }

        public void FindDropdata(int key)
        {
            var i = 0;
            for (; i < GanttItems.GetSelfData().Count; i++)
            {
                if (GanttItems.GetSelfData()[i].TaskID == key)
                {
                    GanttItems.GetSelfData()[i].isParent = true;
                }
            }
        }

        public int FindChildRecords(int? id)
        {
            var count = 0;
            for (var i = 0; i < GanttItems.GetSelfData().Count; i++)
            {
                if (GanttItems.GetSelfData()[i].ParentId == id)
                {
                    count++;
                    count += FindChildRecords(GanttItems.GetSelfData()[i].TaskID);
                }
            }
            return count;
        }
        public void Remove([FromBody] ICRUDModel value)
        {
            if (value.Key != null)
            {
                // GanttItems value = key;
                GanttItems.GetSelfData().Remove(GanttItems.GetSelfData().Where(ds => ds.TaskID == double.Parse(value.Key.ToString())).FirstOrDefault());
            }

        }

View the row drag and drop interactions with server side sample on GitHub

Perform row drag and drop action programmatically

To rearrange rows programmatically in the Gantt component, use the reorderRows method. This method accepts the following parameters:

  • fromIndexes: Indexes of the rows to be moved.
  • toIndex: Target index for placement.
  • position: Placement relative to the target (e.g., above or below).

In the example, a click event on an external button moves the row at index 1 below the row at index 2.

import { Component, ViewChild, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttComponent, GanttModule, RowDDService, EditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule, ButtonModule],
  providers: [RowDDService, EditService, SelectionService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <div style="margin-bottom: 15px;">
      <button ejs-button id="rowdrag" (click)="drag()">Drag and Drop</button>
    </div>
    <ejs-gantt #gantt height="450px" [dataSource]="data" [treeColumnIndex]="1" [splitterSettings]="splitterSettings" [allowRowDragAndDrop]="true" [taskFields]="taskSettings">
      <e-columns>
        <e-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-column>
        <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
        <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
        <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
        <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
      </e-columns>
    </ejs-gantt>`
})

export class AppComponent implements OnInit {
  @ViewChild('gantt') public ganttInstance?: GanttComponent;
  public data: object[] = [];
  public taskSettings: object = {};
  public splitterSettings: object = {};

  ngOnInit(): void {
    this.data = GanttData;
    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      child: 'subtasks'
    };
    this.splitterSettings = {
      position: '75%'
    };
  }

  public drag(): void {
    (this.ganttInstance as GanttComponent).reorderRows([1], 2, 'below');
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Customize the drag and drop action

Customize the drag and drop behavior in the Gantt component using the rowDragStartHelper, rowDragStart, rowDrag, and rowDrop events. These events provide control over the drag lifecycle, allowing precise handling of row interactions.

In this example, drag and drop actions are customized using event hooks. The rowDragStartHelper event prevents dragging for the row where TaskID is 2, while the rowDrop event cancels the drop action for the row where TaskID is 4. Additionally, rowDragStart and rowDrag apply background styling based on the values in the Progress column.

import { Component, ViewChild, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttComponent, GanttModule, RowDDService, EditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { RowDragEventArgs } from '@syncfusion/ej2-angular-grids';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule],
  providers: [RowDDService, EditService, SelectionService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <div style="margin-left: 180px;">
      <p style="color: red;" id="message">{{ message }}</p>
    </div>
    <ejs-gantt #gantt height="450px" [dataSource]="data" [treeColumnIndex]="1" [splitterSettings]="splitterSettings" [allowRowDragAndDrop]="true" (rowDragStartHelper)="rowDragStartHelper($event)" (rowDrop)="rowDrop($event)" (rowDragStart)="rowDragStart($event)" (rowDrag)="rowDrag($event)" [taskFields]="taskSettings">
      <e-columns>
        <e-column field="TaskID" headerText="Task ID" textAlign="Right" [isPrimaryKey]="true" width="90"></e-column>
        <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
        <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
        <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
        <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
      </e-columns>
    </ejs-gantt>`
})

export class AppComponent implements OnInit {
  @ViewChild('gantt') public gantt?: GanttComponent;
  public data: object[] = [];
  public taskSettings: object = {};
  public splitterSettings: object = {};
  public message: string = '';

  ngOnInit(): void {
    this.data = GanttData;
    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      child: 'subtasks'
    };
    this.splitterSettings = {
      position: '75%'
    };
  }

  rowDragStartHelper(args: RowDragEventArgs): void {
    this.message = 'rowDragStartHelper event triggered';
    const draggedTask = (args.data as columnDataType[])[0];
    if (draggedTask.TaskID === 2) {
      args.cancel = true;
      this.message = 'Drag cancelled for TaskID 2';
    }
  }

  rowDragStart(args: RowDragEventArgs): void {
    this.message = 'rowDragStart event triggered';
    const draggedTask = (args.data as columnDataType[])[0];
    if (draggedTask.Progress < 50 && args.rows?.length) {
      args.rows.forEach(row => {
        (row as HTMLElement).style.background = '#ec9ec8ff';
      });
    }
  }

  rowDrag(args: RowDragEventArgs): void {
    this.message = 'rowDrag event triggered';
    if (args.rows?.length && (args.data as columnDataType[])[0].Progress > 50) {
      args.rows.forEach(row => {
        (row as HTMLElement).style.background = '#c5f4fdde';
      });
    }
  }

  rowDrop(args: RowDragEventArgs): void {
    this.message = 'rowDrop event triggered';
    const draggedTask = (args.data as columnDataType[])[0];
    if (draggedTask.TaskID === 4) {
      this.message = 'Drop cancelled for TaskID 4';
      args.cancel = true;
    }
  }
}

export interface columnDataType {
  TaskID: number;
  TaskName: string;
  StartDate: Date;
  Duration: number;
  Progress: number;
  subtasks?: columnDataType[];
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Prevent reordering a row as child to another row

To prevent rows from being reordered as children, set args.cancel to true in the rowDrop event. After canceling the default drop action, use the reorderRows method to reposition the row at a specific index.

In the example, the drop action in Child position is blocked, and the dragged row is reordered above the target row.

import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { GanttComponent, GanttModule } from '@syncfusion/ej2-angular-gantt';
import { RowDDService, EditService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { RowDragEventArgs } from '@syncfusion/ej2-angular-grids';
import { GanttData } from './data';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GanttModule],
  providers: [RowDDService, EditService, SelectionService],
  encapsulation: ViewEncapsulation.None,
  template: `
    <ejs-gantt #gantt id="gantt" height="450px" [dataSource]="data" [treeColumnIndex]="1" [splitterSettings]="splitterSettings" [allowRowDragAndDrop]="true" (rowDrop)="onRowDrop($event)" [taskFields]="taskSettings">
      <e-columns>
        <e-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-column>
        <e-column field="TaskName" headerText="Task Name" textAlign="Left" width="290"></e-column>
        <e-column field="StartDate" headerText="Start Date" textAlign="Right" width="120"></e-column>
        <e-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-column>
        <e-column field="Progress" headerText="Progress" textAlign="Right" width="120"></e-column>
      </e-columns>
    </ejs-gantt>`
})

export class AppComponent {
  @ViewChild('gantt') public gantt?: GanttComponent;
  public data: object[] = [];
  public message: string = '';
  public taskSettings: object = {};
  public splitterSettings: object = {};

  ngOnInit(): void {
    this.data = GanttData;
    this.taskSettings = {
      id: 'TaskID',
      name: 'TaskName',
      startDate: 'StartDate',
      duration: 'Duration',
      progress: 'Progress',
      child: 'subtasks'
    };
    this.splitterSettings = {
      position: '75%'
    };
  }

  public onRowDrop(args: RowDragEventArgs): void {
    if ((args as any).dropPosition === 'middleSegment') {
      args.cancel = true;
      this.gantt?.rowDragAndDropModule.reorderRows([(args.fromIndex as number)], (args.dropIndex as number), 'above');
    }
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

See also