Process the tree node operations using context menu in EJ2 TypeScript TreeView control

28 Jan 202512 minutes to read

You can integrate the context menu with the TreeView control to perform tree view related operations such as adding, removing, and renaming a node.

The following example demonstrates how to manipulate tree view operations in the select event of the context menu.

import { enableRipple } from '@syncfusion/ej2-base';
import { ContextMenu, MenuEventArgs, MenuItemModel, ContextMenuModel, TreeView, BeforeOpenCloseMenuEventArgs, NodeClickEventArgs } from '@syncfusion/ej2-navigations';
enableRipple(true);

/**
 * The node operation in TreeView using context menu
 */
//define the data source for TreeView
let data: { [key: string]: Object }[] = [
    { id: '1', name: 'Local Disk (C:)', hasAttribute: { class: 'remove rename' }, hasChild: true, expanded: true, },
    { id: '2', name: 'Program Files', pid: '1', hasChild: true },
    { id: '3', name: 'Windows NT', pid: '2' },
    { id: '4', name: 'Windows Mail', pid: '2' },
    { id: '5', name: 'Windows Photo Viewer', pid: '2' },
    { id: '6', name: 'Users', pid: '1', hasChild: true, expanded: true },
    { id: '7', name: 'Smith', pid: '6' },
    { id: '8', name: 'Public', pid: '6' },
    { id: '9', name: 'Admin', pid: '6' },
    { id: '10', name: 'Windows', pid: '1', hasChild: true },
    { id: '11', name: 'Boot', pid: '10' },
    { id: '12', name: 'FileManager', pid: '10' },
    { id: '13', name: 'System32', pid: '10' },
    { id: '14', name: 'Local Disk (D:)', hasAttribute: { class: 'remove' }, hasChild: true },
    { id: '15', name: 'Personals', pid: '14', hasChild: true },
    { id: '16', name: 'My photo.png', pid: '15' },
    { id: '17', name: 'Rental document.docx', pid: '15' },
    { id: '18', name: 'Pay slip.pdf', pid: '15' },
    { id: '19', name: 'Projects', pid: '14', hasChild: true },
    { id: '20', name: 'ASP Application', pid: '19' },
    { id: '21', name: 'TypeScript Application', pid: '19' },
    { id: '22', name: 'React Application', pid: '19' },
    { id: '23', name: 'Office', pid: '14', hasChild: true },
    { id: '24', name: 'Work details.docx', pid: '23' },
    { id: '25', name: 'Weekly report.docx', pid: '23' },
    { id: '26', name: 'Wish list.csv', pid: '23' },
    { id: '27', name: 'Local Disk (E:)', hasAttribute: { class: 'remove' }, hasChild: true },
    { id: '28', name: 'Pictures', pid: '27', hasChild: true },
    { id: '29', name: 'Wind.jpg', pid: '28' },
    { id: '30', name: 'Stone.jpg', pid: '28' },
    { id: '31', name: 'Home.jpg', pid: '28' },
    { id: '32', name: 'Documents', pid: '27', hasChild: true },
    { id: '33', name: 'Environment Pollution.docx', pid: '32' },
    { id: '34', name: 'Global Warming.ppt', pid: '32' },
    { id: '35', name: 'Social Network.pdf', pid: '32' },
    { id: '36', name: 'Study Materials', pid: '27', hasChild: true },
    { id: '37', name: 'UI-Guide.pdf', pid: '36' },
    { id: '38', name: 'Tutorials.zip', pid: '36' },
    { id: '39', name: 'TypeScript.7z', pid: '36' }
];

// Render the TreeView by mapping its fields property with data source properties
let treeObj: TreeView = new TreeView({
    fields: { dataSource: data, id: 'id', text: 'name', parentID: 'pid', hasChildren: 'hasChild', htmlAttributes: 'hasAttribute' },
    nodeClicked: nodeClick
});
treeObj.appendTo('#tree');
function nodeClick(args: NodeClickEventArgs) {
    if (args.event.which === 3) {
        treeObj.selectedNodes = [args.node.getAttribute('data-uid')]
    }
}

//Render the context menu with target as TreeView
let menuItems: MenuItemModel[] = [
    { text: 'Add New Item' },
    { text: 'Rename Item' },
    { text: 'Remove Item' }
];
let menuOptions: ContextMenuModel = {
    target: '#tree',
    items: menuItems,
    select: menuClick,
    beforeOpen: beforeOpen
};
let menuObj: ContextMenu = new ContextMenu(menuOptions, '#contextmenu');

let index: number = 1;
function menuClick(args: MenuEventArgs) {
    let targetNodeId: string = treeObj.selectedNodes[0];
    if (args.item.text == "Add New Item") {
        let nodeId: string = "tree_" + index;
        let item: { [key: string]: Object } = { id: nodeId, name: "New Folder" };
        treeObj.addNodes([item], targetNodeId, null);
        index++;
        data.push(item);
        treeObj.beginEdit(nodeId);
    }
    else if (args.item.text == "Remove Item") {
        treeObj.removeNodes([targetNodeId]);
    }
    else if (args.item.text == "Rename Item") {
        treeObj.beginEdit(targetNodeId);
    }
}

function beforeOpen(args: BeforeOpenCloseMenuEventArgs) {
    let targetNodeId: string = treeObj.selectedNodes[0];
    let targetNode: Element = document.querySelector('[data-uid="' + targetNodeId + '"]') as Element;
    if (targetNode.classList.contains('remove')) {
        menuObj.enableItems(['Remove Item'], false);
    }
    else {
        menuObj.enableItems(['Remove Item'], true);
    }
    if (targetNode.classList.contains('rename')) {
        menuObj.enableItems(['Rename Item'], false);
    }
    else {
        menuObj.enableItems(['Rename Item'], true);
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 for TreeView </title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for TreeView UI Control" />
    <meta name="author" content="Syncfusion" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/29.1.33/ej2-navigations/styles/material.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='loader'>Loading....</div>
    <div id='container'>
        <div id='treeparent'>
            <div id="tree"></div>
            <ul id="contextmenu"></ul>
        </div>
    </div>
    <style>
        #treeparent {
            display: block;
            max-width: 350px;
            max-height: 350px;
            margin: auto;
            overflow: auto;
            border: 1px solid #dddddd;
            border-radius: 3px;
        }
    </style>
</body>

</html>
#container {
  visibility: hidden;
}

#loader {
  color: #008cff;
  height: 40px;
  width: 30%;
  position: absolute;
  font-family: 'Helvetica Neue', 'calibiri';
  font-size: 14px;
  top: 45%;
  left: 45%;
}