How to restrict drag-and-drop for particular tree nodes in Angular Tree View

31 Aug 202611 minutes to read

You are able to restrict drag and drop operations to allow files to be dropped only under folders. This can be achieved by using nodeDragStop and nodeDragging events of TreeView.

Implementation approach

The events used here expose the following useful arguments:

Event Useful argument fields
nodeDragging args.draggedNode, args.dropTarget, args.dropIndicator ("e-drop-in" child / "e-drop-next" sibling / "e-drop-no" restrict)
nodeDragStop args.draggedNode, args.dropTarget, args.dropIndicator, args.cancel

To restrict drag and drop operations:

  1. Enable drag and drop: Set the allowDragAndDrop property to true.
  2. Handle the nodeDragging event: Use this event to provide visual feedback by modifying drop indicators.
  3. Handle the nodeDragStop event: Implement validation logic and set args.cancel = true to cancel an invalid drop.
  4. Identify node types: Determine whether nodes are files or folders using a property on the node data record.
  5. Apply conditional validation: Allow the drop only when the target node and drop indicator match the rules defined in your business logic.
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import { TreeViewModule } from '@syncfusion/ej2-angular-navigations'
import { Component, Inject, ViewChild } from '@angular/core';
import { DragAndDropEventArgs } from '@syncfusion/ej2-angular-navigations';

@Component({
    imports: [
        FormsModule, TreeViewModule
    ],
    standalone: true,
    selector: 'app-container',
    template: `<div id='treeparent'><ejs-treeview id="icons" [fields]='field' sortOder='Ascending' allowDragAndDrop='allowDragAndDrop' (nodeDragStop)='dragStop($event)' (nodeDragging)='nodeDrag($event)'></ejs-treeview></div>`
})
export class AppComponent {
    // Hierarchical data source for TreeView component
    public hierarchicalData: Object[] = [
        {
            nodeId: '01', nodeText: 'Music', icon: 'folder',
            nodeChild: [
                { nodeId: '01-01', nodeText: 'Gouttes.mp3', icon: 'audio' }
            ]
        },
        {
            nodeId: '02', nodeText: 'Videos', icon: 'folder',
            nodeChild: [
                { nodeId: '02-01', nodeText: 'Naturals.mp4', icon: 'video' },
                { nodeId: '02-02', nodeText: 'Wild.mpeg', icon: 'video' },
            ]
        },
        {
            nodeId: '03', nodeText: 'Documents', icon: 'folder',
            nodeChild: [
                { nodeId: '03-01', nodeText: 'Environment Pollution.docx', icon: 'docx' },
                { nodeId: '03-02', nodeText: 'Global Water, Sanitation, & Hygiene.docx', icon: 'docx' },
                { nodeId: '03-03', nodeText: 'Global Warming.ppt', icon: 'ppt' },
                { nodeId: '03-04', nodeText: 'Social Network.pdf', icon: 'pdf' },
                { nodeId: '03-05', nodeText: 'Youth Empowerment.pdf', icon: 'pdf' },
            ]
        },
        {
            nodeId: '04', nodeText: 'Pictures', icon: 'folder', expanded: true,
            nodeChild: [
                {
                    nodeId: '04-01', nodeText: 'Camera Roll', icon: 'folder', expanded: true,
                    nodeChild: [
                        { nodeId: '04-01-01', nodeText: 'WIN_20160726_094117.JPG', image: 'https://ej2.syncfusion.com/demos/src/treeview/images/employees/9.png' },
                        { nodeId: '04-01-02', nodeText: 'WIN_20160726_094118.JPG', image: 'https://ej2.syncfusion.com/demos/src/treeview/images/employees/3.png' },
                    ]
                },
                { nodeId: '04-02', nodeText: 'Wind.jpg', icon: 'images' },
                { nodeId: '04-03', nodeText: 'Stone.jpg', icon: 'images' },
            ]
        },
        {
            nodeId: '05', nodeText: 'Downloads', icon: 'folder',
            nodeChild: [
                { nodeId: '05-01', nodeText: 'UI-Guide.pdf', icon: 'pdf' },
                { nodeId: '05-02', nodeText: 'Tutorials.zip', icon: 'zip' },
                { nodeId: '05-03', nodeText: 'Game.exe', icon: 'exe' },
                { nodeId: '05-04', nodeText: 'TypeScript.7z', icon: 'zip' },
            ]
        }
    ];
    public field: Object = { dataSource: this.hierarchicalData, id: 'nodeId', text: 'nodeText', child: 'nodeChild', iconCss: 'icon', imageUrl: 'image' };
    public allowDragAndDrop: boolean = true;

    public nodeDrag(args: DragAndDropEventArgs): void {
        if (args.droppedNode != null && args.droppedNode.getElementsByClassName('folder') && args.droppedNode.getElementsByClassName('folder').length === 0) {
            args.dropIndicator = 'e-no-drop';
        }
    }

    public dragStop(args: DragAndDropEventArgs): void {
        if (args.droppedNode != null && args.droppedNode.getElementsByClassName('folder') && args.droppedNode.getElementsByClassName('folder').length === 0) {
            args.cancel = true;
        }
    }


}
@import 'node_modules/@syncfusion/ej2-base/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-inputs/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-buttons/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-angular-base/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-angular-navigations/styles/material3.css';
@import 'node_modules/@syncfusion/ej2-angular-inputs/styles/material3.css';

#treeparent {
    display: block;
    max-width: 400px;
    max-height: 320px;
    margin: auto;
    overflow: auto;
    border: 1px solid #dddddd;
    border-radius: 3px;
}

.e-treeview .e-list-img {
    width: 25px;
    height: 25px;
}

/* Loading sprite image for TreeView */
.e-treeview .e-list-icon {
    background-repeat: no-repeat;
    background-image: url(https://ej2.syncfusion.com/demos/src/treeview/images/icons/file_icons.png);
    height: 20px;
}

/* Specify the icon positions based upon class name */
.e-treeview .e-list-icon.folder {
    background-position: -10px -552px;
}

.e-treeview .e-list-icon.docx {
    background-position: -10px -20px;
}

.e-treeview .e-list-icon.ppt {
    background-position: -10px -48px;
}

.e-treeview .e-list-icon.pdf {
    background-position: -10px -104px;
}

.e-treeview .e-list-icon.images {
    background-position: -10px -132px;
}

.e-treeview .e-list-icon.zip {
    background-position: -10px -188px;
}

.e-treeview .e-list-icon.audio {
    background-position: -10px -244px;
}

.e-treeview .e-list-icon.video {
    background-position: -10px -272px;
}

.e-treeview .e-list-icon.exe {
    background-position: -10px -412px;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));