Perform tree node actions using context menu

27 Aug 202518 minutes to read

You can integrate the context menu with the TreeView component to perform essential TreeView operations such as adding, removing, and renaming nodes. This integration provides users with an intuitive right-click interface for managing tree structure and node content.

The following example demonstrates how to use the context menu’s select event to handle TreeView operations including node addition, deletion, and text editing. The implementation shows proper event handling and TreeView method usage for comprehensive node management.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import { TreeViewModule, ContextMenuModule } from '@syncfusion/ej2-angular-navigations';
import { NodeClickEventArgs, BeforeOpenCloseMenuEventArgs, MenuEventArgs, MenuItemModel } from '@syncfusion/ej2-navigations';
import { Component, Inject, ViewChild } from '@angular/core';
import { TreeViewComponent, ContextMenuComponent } from '@syncfusion/ej2-angular-navigations';

@Component({
    imports: [
        FormsModule, TreeViewModule, ContextMenuModule
    ],
    standalone: true,
    selector: 'app-container',
    template: `<div id='treeparent'>
        <ejs-treeview  id='tree' #treevalidate [fields]='field' (nodeClicked)='nodeclicked($event)'></ejs-treeview>
        </div>
        <ejs-contextmenu #contentmenutree id='contentmenutree' target='#tree' [items]='menuItems' (beforeOpen)='beforeopen($event)' (select)='menuclick($event)'></ejs-contextmenu>`
})
export class AppComponent {

    public hierarchicalData: Object[] = [
        {
            id: '01', name: 'Local Disk (C:)', expanded: true, hasAttribute: { class: 'remove rename' },
            subChild: [
                {
                    id: '01-01', name: 'Program Files',
                    subChild: [
                        { id: '01-01-01', name: 'Windows NT' },
                        { id: '01-01-02', name: 'Windows Mail' },
                        { id: '01-01-03', name: 'Windows Photo Viewer' },
                    ]
                },
                {
                    id: '01-02', name: 'Users', expanded: true,
                    subChild: [
                        { id: '01-02-01', name: 'Smith' },
                        { id: '01-02-02', name: 'Public' },
                        { id: '01-02-03', name: 'Admin' },
                    ]
                },
                {
                    id: '01-03', name: 'Windows',
                    subChild: [
                        { id: '01-03-01', name: 'Boot' },
                        { id: '01-03-02', name: 'FileManager' },
                        { id: '01-03-03', name: 'System32' },
                    ]
                },
            ]
        },
        {
            id: '02', name: 'Local Disk (D:)', hasAttribute: { class: 'remove' },
            subChild: [
                {
                    id: '02-01', name: 'Personals',
                    subChild: [
                        { id: '02-01-01', name: 'My photo.png' },
                        { id: '02-01-02', name: 'Rental document.docx' },
                        { id: '02-01-03', name: 'Pay slip.pdf' },
                    ]
                },
                {
                    id: '02-02', name: 'Projects',
                    subChild: [
                        { id: '02-02-01', name: 'ASP Application' },
                        { id: '02-02-02', name: 'TypeScript Application' },
                        { id: '02-02-03', name: 'React Application' },
                    ]
                },
                {
                    id: '02-03', name: 'Office',
                    subChild: [
                        { id: '02-03-01', name: 'Work details.docx' },
                        { id: '02-03-02', name: 'Weekly report.docx' },
                        { id: '02-03-03', name: 'Wish list.csv' },
                    ]
                },
            ]
        },
        {
            id: '03', name: 'Local Disk (E:)', icon: 'folder', hasAttribute: { class: 'rename' },
            subChild: [
                {
                    id: '03-01', name: 'Pictures',
                    subChild: [
                        { id: '03-01-01', name: 'Wind.jpg' },
                        { id: '03-01-02', name: 'Stone.jpg' },
                        { id: '03-01-03', name: 'Home.jpg' },
                    ]
                },
                {
                    id: '03-02', name: 'Documents',
                    subChild: [
                        { id: '03-02-01', name: 'Environment Pollution.docx' },
                        { id: '03-02-02', name: 'Global Warming.ppt' },
                        { id: '03-02-03', name: 'Social Network.pdf' },
                    ]
                },
                {
                    id: '03-03', name: 'Study Materials',
                    subChild: [
                        { id: '03-03-01', name: 'UI-Guide.pdf' },
                        { id: '03-03-02', name: 'Tutorials.zip' },
                        { id: '03-03-03', name: 'TypeScript.7z' },
                    ]
                },
            ]
        }
    ];
    // Mapping TreeView fields property with data source properties
    public field: Object = { dataSource: this.hierarchicalData, id: 'id', text: 'name', child: 'subChild', htmlAttributes: 'hasAttribute' };

    @ViewChild('treevalidate') treevalidate?: TreeViewComponent;
    @ViewChild('contentmenutree') contentmenutree?: ContextMenuComponent;

    public nodeclicked(args: NodeClickEventArgs) {
        if (args.event.which === 3) {
            (this.treevalidate as TreeViewComponent).selectedNodes = [args.node.getAttribute('data-uid') as string];
        }
    }

    //Render the context menu with target as Treeview
    public menuItems: MenuItemModel[] = [
        { text: 'Add New Item' },
        { text: 'Rename Item' },
        { text: 'Remove Item' }
    ];

    public index: number = 1;
    public menuclick(args: MenuEventArgs) {
        let targetNodeId: string = this.treevalidate?.selectedNodes[0] as string;
        if (args.item.text == "Add New Item") {
            let nodeId: string = "tree_" + this.index;
            let item: { [key: string]: Object } = { id: nodeId, name: "New Folder" };
            this.treevalidate?.addNodes([item], targetNodeId, null as any);
            this.index++;
            this.hierarchicalData.push(item);
            this.treevalidate?.beginEdit(nodeId);
        }
        else if (args.item.text == "Remove Item") {
            this.treevalidate?.removeNodes([targetNodeId]);
        }
        else if (args.item.text == "Rename Item") {
            this.treevalidate?.beginEdit(targetNodeId);
        }
    }

    public beforeopen(args: BeforeOpenCloseMenuEventArgs) {
        let targetNodeId: string = this.treevalidate?.selectedNodes[0] as string;
        let targetNode: Element = document.querySelector('[data-uid="' + targetNodeId + '"]') as Element;
        if (targetNode.classList.contains('remove')) {
            this.contentmenutree?.enableItems(['Remove Item'], false);
        }
        else {
            this.contentmenutree?.enableItems(['Remove Item'], true);
        }
        if (targetNode.classList.contains('rename')) {
            this.contentmenutree?.enableItems(['Rename Item'], false);
        }
        else {
            this.contentmenutree?.enableItems(['Rename Item'], true);
        }
    }
}
@import 'node_modules/@syncfusion/ej2-base/styles/material.css';
@import 'node_modules/@syncfusion/ej2-inputs/styles/material.css';
@import 'node_modules/@syncfusion/ej2-buttons/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-base/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-navigations/styles/material.css';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));