Row drag and drop in React Treegrid component

2 Jan 202419 minutes to read

The TreeGrid rows can be reordered, dropped to another TreeGrid or custom control by enabling the allowRowDragAndDrop to true.

To use row drag and drop, inject the RowDD module in the TreeGrid.

Drag and drop within Tree Grid

The TreeGrid row drag and drop allows you to drag and drop TreeGrid rows on the same TreeGrid using drag icon. To enable row drag and drop, set the allowRowDragAndDrop to true. It provides the way to drop the row above, below or child to the target row with respective to the target row position.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';
class App extends React.Component {
    selectionSettings = { type: 'Multiple' };
    render() {
        return <TreeGridComponent dataSource={sampleData} allowRowDragAndDrop={true} treeColumnIndex={1} childMapping='subtasks' height='270' selectionSettings={this.selectionSettings}>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right'/>
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>;
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD, RowDropSettingsModel, SelectionSettingsModel } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';

class App extends React.Component<{}, {}>{

    public selectionSettings: SelectionSettingsModel = { type: 'Multiple' };

    render() {
        return <TreeGridComponent dataSource={sampleData} allowRowDragAndDrop={true} treeColumnIndex={1} childMapping='subtasks' height='270' selectionSettings={this.selectionSettings} >
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));

  • Selection feature must be enabled for row drag and drop.
  • Multiple rows can be selected by clicking and dragging inside the treegrid.
  • For multiple row selection, the type property must be set to multiple.
  • The isPrimaryKey property is necessary to perform row drag and drop operation.

Drag and drop to another Tree Grid

To drag and drop between two TreeGrid, enable the allowRowDragAndDrop property and specify the target TreeGrid ID in targetID property of rowDropSettings.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, RowDD, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';
class Source extends React.Component {
    data = sampleData;
    rowDropSettings = { targetID: 'DestGrid' };
    selectionSettings = { type: 'Multiple' };
    style = { marginBottom: '20px' };
    render() {
        return <TreeGridComponent id='TreeGrid' dataSource={sampleData} treeColumnIndex={1} allowRowDragAndDrop={true} rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings} childMapping='subtasks' height='275'>
                <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
          </TreeGridComponent >;
    }
}
class Target extends React.Component {
    data = [];
    rowDropSettings = { targetID: 'TreeGrid' };
    selectionSettings = { type: 'Multiple' };
    render() {
        return <TreeGridComponent treeColumnIndex={1} id='DestGrid' allowRowDragAndDrop={true} rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings} childMapping='subtasks' height='275'>
        <ColumnsDirective>
        <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
        <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
        <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
        <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
      </ColumnsDirective>
      <Inject services={[RowDD]}/>
</TreeGridComponent>;
    }
}
   
function App() {
    return <div>
            <Source></Source>
            <Target></Target>
           </div>;
}
ReactDOM.render(<App />, document.getElementById('treegrid'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, RowDD, ColumnsDirective, ColumnDirective, RowDropSettingsModel, SelectionSettingsModel, Inject } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';

class Source extends React.Component<{}, {}>{
    public data: Object[] = sampleData;
    public rowDropSettings: RowDropSettingsModel = { targetID: 'DestGrid' };
    public selectionSettings: SelectionSettingsModel = { type: 'Multiple' };
    public style = { marginBottom: '20px' };
    render() {
        return <TreeGridComponent id='TreeGrid' dataSource={sampleData} treeColumnIndex={1} allowRowDragAndDrop={true}
        rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings}
         childMapping='subtasks' height='275'>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}

class Target extends React.Component<{}, {}>{
    public data: Object[] = [];
    public rowDropSettings: RowDropSettingsModel = { targetID: 'TreeGrid' };
    public selectionSettings: SelectionSettingsModel = { type: 'Multiple' };
    render() {
        return <TreeGridComponent treeColumnIndex={1} id='DestGrid' allowRowDragAndDrop={true}
        rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings}
         childMapping='subtasks' height='275'>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}


function App(){
    return <div>
            <Source></Source>
            <Target></Target>
           </div>
}

ReactDOM.render(<App />, document.getElementById('treegrid'));

Drag and drop events

The following events are triggered while drag and drop the treegrid rows.

rowDragStartHelper - Triggers when click the drag icon or treegrid row and this event is used to customize the drag element based on user criteria.

rowDragStart -Triggers when starts to drag the treegrid row.

rowDrag - Triggers while dragging the treegrid row.

rowDrop - Triggers when a drag element is dropped on the target element.

Prevent reordering a row as child to another row

You can prevent the default behavior of dropping rows as children to the target by setting the cancel property to true in rowDrop event argument. You can also change the drop position after cancelling using reorderRows method.

In the below example drop action is cancelled and dropped above to target row.

import * as React from 'react';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';
class App extends React.Component {
    rowDrop(args) {
        if (args.dropPosition == 'middleSegment') {
            args.cancel = true;
            this.treegridInstance.reorderRows([args.fromIndex], args.dropIndex, 'above');
        }
        render();
        {
            return <TreeGridComponent ref={(treegrid) => (this.treegridInstance = treegrid)} allowRowDragAndDrop={true} dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' height='270' rowDrop={this.rowDrop.bind(this)}>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right'/>
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>;
        }
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD, RowDropSettingsModel, SelectionSettingsModel } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';

class App extends React.Component<{}, {}>{
       public treegridInstance: TreeGridComponent;
       public rowDrop(args: any) {
          if (args.dropPosition == 'middleSegment') {
               args.cancel = true;
               this.treegridInstance.reorderRows([args.fromIndex], args.dropIndex, 'above');
          }
       }
       render() {
        return <TreeGridComponent ref={(treegrid) => (this.treegridInstance = treegrid)} allowRowDragAndDrop={true} dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' height='270' rowDrop={this.rowDrop.bind(this)} >
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));