Node Editing in Angular Tree View
31 Aug 202616 minutes to read
The TreeView component provides in-place node editing functionality by setting the allowEditing property to true. To directly edit nodes in place, double-click the TreeView node or select the node and press the F2 key.
When editing is completed by losing focus or pressing the Enter key, the modified node’s text is saved automatically. To cancel editing without saving changes, press the Escape key. This discards the edited text and retains the original TreeView node text.
Programmatic editing
Node editing can also be performed programmatically. Pass a node ID to the beginEdit method to create an inline edit textbox for that node.
@ViewChild('tree') tree: TreeViewComponent;
public editNode(nodeId: string): void {
this.tree.beginEdit(nodeId); // Opens an inline edit textbox for the specified node
}You can also wire beginEdit to a button click handler so the user can trigger edit mode from the page instead of a double-click or F2.
Editing events
The component exposes events to validate editing, react to changes, and prevent saves:
| Event | When it fires | Useful event arguments |
|---|---|---|
nodeEditing |
Before a node enters edit mode (typically on F2 or double-click). Use this event to decide whether editing is allowed. |
args.node, args.nodeData
|
nodeEdited |
Before the edited text is saved (Enter or focus loss). Cancel the save by setting args.cancel = true. Use this event for validation such as disallowing empty text. |
args.oldText, args.newText, args.node, args.nodeData, args.cancel
|
The following example shows how to cancel editing in the nodeEdited event when the user enters only whitespace:
public onNodeEdited(args: NodeEditEventArgs): void {
if (!args.newText || args.newText.trim() === '') {
args.cancel = true; // Prevent the empty or whitespace text from being saved
}
}If the user presses Escape, the editor closes without firing the
nodeEditedevent.
In the following example, the first level node’s text cannot be changed, but all other level nodes’ text can be modified.
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import { TreeViewModule, TreeViewComponent } from '@syncfusion/ej2-angular-navigations'
import { Component, ViewChild } from '@angular/core';
import { NodeCheckEventArgs } from '@syncfusion/ej2-navigations';
@Component({
imports: [
FormsModule, TreeViewModule
],
standalone: true,
selector: 'app-container',
// specifies the template string for the TreeView component
template: `<div id='treeparent'><ejs-treeview id='treeelement' [fields]='field' [allowEditing]='allowEditing' (nodeEditing)='editing($event)'></ejs-treeview></div>`
})
export class AppComponent {
@ViewChild('samples')
public tree?: TreeViewComponent;
constructor() {
}
// defined the array of data
public hierarchicalData: Object[] = [
{
id: '01', name: 'Local Disk(C:)', expanded: true,
subChild: [
{
id: '01-01', name: 'Program Files',
subChild: [
{ id: '01-01-01', name: '7-Zip' },
{ id: '01-01-02', name: 'Git' },
{ id: '01-01-03', name: 'IIS Express' },
]
},
{
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:)',
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',
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' },
]
},
]
}
];
// maps the appropriate column to fields property
public field: Object = { dataSource: this.hierarchicalData, id: 'id', text: 'name', child: 'subChild' };
// enable the editing options to the TreeView
public allowEditing: boolean = true;
//Bind the nodeChecked event
public editing(args: NodeCheckEventArgs) {
//check whether node is root node or not
if (args.node.parentNode?.parentNode?.nodeName !== "LI") {
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';import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));