a suite of UI Components for development of web apps
If you have any questions, don't hesitate to contact us at support@lidorsystems.com
Advanced User Interface Controls and Components
Created: 19 May 2017
Angular TreeView component by default doesn't have a Context Menu attached. Having a context menu is useful in cases when you want to extend the TreeView functionality and provide better user interface. For example, if you want to edit or copy/paste items, you can create a context menu with options that can provide that kind of functionality. In this article, you will learn how to do that.
If you have any questions, don't hesitate to contact us at support@lidorsystems.com
To open the context menu, right-click anywhere inside the TreeView space. Four options will appear:
As demo shows, using a context menu you can dynamically edit and move items in the Angular TreeView.
At first, to add a context menu to the TreeView, you only need to create an object that holds all menu settings. Then add the iuiContextMenu property in HTML and link it with the menu settings object. In addition, add an event handler for menuItemClick event, which is fired when a menu option is clicked:
// Context Menu settings
private menuSettings: any = {
appRef: null,
items: [
{ id: 1, text: "Edit" },
{ id: 2, type: "separator" },
{ id: 3, text: "Cut" },
{ id: 4, text: "Copy" },
{ id: 5, text: "Paste" }
]
}
// ContextMenu events ----------------------------------------------------------------
menuItemClick(e: any){
if (e.item){
// Action depends on selected menu option
switch (e.item.id){
case 1: // Edit
break;
case 3: // Cut
break;
case 4: // Copy
break;
case 5: // Paste
break;
}
}
}
<iui-treeview [items]="data" [controlStyle]="treeStyle" [iuiContextMenu]="menuSettings" (itemClick)="menuItemClick($event)" #treeview>
<template let-item>
<span *ngIf="item!=editItem" [ngStyle]="{ opacity: item == moveItem ? 0.5 : 1 }">{{item.text}}</span>
<input *ngIf="item==editItem" type="text" [(ngModel)]="item.text" (keydown)="editorKeyDown($event)" [iuiFocus]="editorFocused" (focus)="selectContent($event)" (blur)="editorLostFocus()" />
</template>
</iui-treeview>
Note Make sure that the appRef of menu object has its value set to point to the reference of the root component. This is required for dynamic creation of ContextMenu and its visibility.
Now, whenever TreeView is right-clicked, the context menu will appear. However, it is not yet functional.
To edit items, at first you need to have some kind of text editor. For example, you can use the input element that will appear whenever the item is in edit mode, otherwise will remain hidden. The item template in this case is:
private isEditActive: boolean = false;
private editItem: any = null;
private originalText: string = '';
private editorFocused: boolean = false;
// Selects the whole text in the text editor
selectContent(e: any){
if (e.target){
setTimeout(function(){
e.target.setSelectionRange(0, e.target.value.length);
}, 1);
}
}
<iui-treeview [items]="data" [controlStyle]="treeStyle" [iuiContextMenu]="menuSettings" (itemClick)="menuItemClick($event)" #treeview>
<template let-item>
<span *ngIf="item!=editItem" [ngStyle]="{ opacity: item == moveItem ? 0.5 : 1 }">{{item.text}}</span>
<input *ngIf="item==editItem" type="text" [(ngModel)]="item.text" (keydown)="editorKeyDown($event)" [iuiFocus]="editorFocused" (focus)="selectContent($event)" (blur)="editorLostFocus()" />
</template>
</iui-treeview>
Now we can add functionality to Edit option of the context menu. In menuItemClick event handler, add a code that will check for the id value of the menu option and provide a corresponding action In case of Edit option, show a text editor in place of selected item:
menuItemClick(e: any){
if (e.item){
// Action depends on selected menu option
switch (e.item.id){
case 1: // Edit
this.showEditor(this.treeview.selectedItem);
break;
case 3: // Cut
break;
case 4: // Copy
break;
case 5: // Paste
break;
}
}
}
showEditor(item: any){
// A timeout is required in this case, because when edit option from context menu is selected
// there is a small delay prior context menu closes and focus is transfered from context menu to the item
// In other cases (when context menu is not used), the timout is not needed
let self = this;
let editTimeout = setTimeout(function(){
self.originalText = item.text;
self.isEditActive = true;
self.editItem = item;
self.editorFocused = true;
clearTimeout(editTimeout);
}, 1);
}
The showEditor method sets the selected item in edit mode. This updates the HTML, so that now the item label is hidden and the text editor appears.
When text editor is active, to confirm changes press ENTER, to cancel them press ESCAPE or click anywhere outside the editor. This is done by handling the keyDown event for the input element, and blur event handler that closes the editor when you click outside of its space.
closeEditor(){
this.editItem = null;
this.originalText = '';
this.editorFocused = false;
}
editorKeyDown(e: any){
if (this.editItem){
switch (e.keyCode){
case 13: // ENTER
this.closeEditor();
break;
case 27: // ESCAPE
this.editItem.text = this.originalText;
this.closeEditor();
break;
}
}
}
editorLostFocus(){
if (this.editItem)
this.editItem.text = this.originalText;
this.closeEditor();
}
Other options from the context menu will move the item or its copy at new position within the TreeView.
The Cut option simply marks the selected item as movable. This updates the style of the item in HTML so that it will appear as grayed.
The Copy option creates a deep copy of the selected item.
menuItemClick(e: any){
if (e.item){
// Action depends on selected menu option
switch (e.item.id){
case 1: // Edit
this.showEditor(this.treeview.selectedItem);
break;
case 3: // Cut
// Mark the currently selected item for moving
this.moveItem = this.treeview.selectedItem;
break;
case 4: // Copy
// Create a clone of currently selected item
this.clone = this.treeview.cloneItem(this.treeview.selectedItem);
break;
case 5: // Paste
break;
}
}
}
Finally, the Paste option check whether item that is pasted is the marked item or a clone. If it is the marked item, it is removed from the tree hierarchy and then placed at position below the currently selected item. To place the pasted item below selected item, we need to locate the parent item of selected item and then call the insertItemAt method with new index at which item will be placed.
menuItemClick(e: any){
if (e.item){
// Action depends on selected menu option
switch (e.item.id){
case 1: // Edit
this.showEditor(this.treeview.selectedItem);
break;
case 3: // Cut
// Mark the currently selected item for moving
this.moveItem = this.treeview.selectedItem;
break;
case 4: // Copy
// Create a clone of currently selected item
this.clone = this.treeview.cloneItem(this.treeview.selectedItem);
break;
case 5: // Paste
let pasteItem: any = null;
// Get the item to be pasted
// From CUT
if (this.moveItem){
pasteItem = this.moveItem;
this.treeview.removeItem(pasteItem);
}
// From COPY
else if (this.clone)
pasteItem = this.clone;
// Paste the item at position below the selected item
if (pasteItem){
let parent: any = this.treeview.getItemParent(this.treeview.selectedItem);
let list: Array = parent && parent.items ? parent.items : this.data;
if (list){
let index: number = list.indexOf(this.treeview.selectedItem);
if (index >= 0)
this.treeview.insertItemAt(pasteItem, index+1, parent);
}
}
this.moveItem = null;
break;
}
}
}
Angular TreeView component doesn't have a built-in ContextMenu functionality. You can add this functionality, by using the ContextMenu component. You can create custom context menu with options that allows you to edit, copy and paste items in the TreeView.
The TreeView component is part of IntegralUI Web.