LIDOR SYSTEMS

Advanced User Interface Controls and Components

Add Item Dynamically in Angular TreeView

Created: 23 Oct 2017

You can populate the Angular TreeView by loading predefined data from a local or remote data source, or you can create the tree structure on the fly, in the client. In this article, you will learn how to add command buttons on the right side of each item, which you can use to add new parent and child items dynamically.

TreeView component is part of IntegralUI Web
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

By default, command buttons are hidden from the view. When you move the mouse cursor over some item, three buttons will appear on the right side:

  • Add Root - which creates a new item and place it at the end of the tree as root
  • Add Child - which creates a new item as child of corresponding item
  • Delete - which removes the item from the tree

In addition, to change the item label, click on its label and a text editor will popup where you can enter a new label.

How to Add Root, Add Child and Delete Buttons to Items in Angular TreeView

In order to create the tree structure from within the TreeView UI, you can use command buttons with different functionality, like:

  • Creating an item and placing it to the root of the tree
  • Creating an item and placing it as a child of specified item
  • Option to edit and delete items

In this way, you can modify the tree hierarchy on the fly, from within the TreeView.

Each item has a template where you can add custom HTML elements. In case of command buttons, you can use the <button> element, or like in this example the <span> element with an icon as a background. For example:

// 
// app.module.ts
//

import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { IntegralUIModule } from './integralui/integralui.module';

import { AppComponent }   from './app.component';

@NgModule({
    imports:      [ 
          BrowserModule, 
          FormsModule, 
          IntegralUIModule
    ],
    declarations: [ 
        AppComponent, 
    ],
    bootstrap: [ AppComponent ]
})
export class AppModule { }

// 
// app.component.ts
//

import { Component, ViewContainerRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { IntegralUITreeView } from './integralui/components/integralui.treeview';

@Component({
    selector: 'iui-app',
    templateUrl: 'app.template.html',
    styleUrls: ['sample-styles.css'],
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    @ViewChild('application', {read: ViewContainerRef}) applicationRef: ViewContainerRef;
    @ViewChild('treeview') treeview: IntegralUITreeView;

    public items: Array;

    private isEditActive: boolean = false;
    public editItem: any = null;
    private originalText: string = '';
    public editorFocused: boolean = false;
    public hoverItem: any = null;
    
    public ctrlStyle: any = {
        general: {
            normal: 'trw-add-dynamic'
        }
    }

    private itemCount: number = 1;

    constructor(){
        this.items = [
            { text: "Item 1" }
        ];

    } 

    // Add/Remove ------------------------------------------------------------------------
                
    createNewItem(){
        this.itemCount++;

        return { text: "Item " + this.itemCount };
    }

    addRoot(){
        let item: any = this.createNewItem();
        
        this.treeview.addItem(item);
        this.showEditor(item);
    }

    addChild(parent: any){
        let item: any = this.createNewItem();
        
        this.treeview.addItem(item, parent);
        this.showEditor(item);
    }

    deleteItem(item: any){
        if (item)
            this.treeview.removeItem(item);
    }

    // Edit ------------------------------------------------------------------------------

    // 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);
        }
    }

    showEditor(item: any){
        this.originalText = item.text;
        this.isEditActive = true;
        this.editItem = item;
        this.editorFocused = true;

        item.allowDrag = false;
    }

    closeEditor(){
        if (this.editItem)
            this.editItem.allowDrag = true;
            
        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();
    }
}
                            
// 
// app.template.html
//

<div #application>
    <iui-treeview [items]="items" [appRef]="applicationRef" [controlStyle]="ctrlStyle" #treeview>
        <ng-template let-item>
            <div (mouseenter)="hoverItem=item" (mouseleave)="hoverItem=null">
                <span *ngIf="item!=editItem" (mouseup)="showEditor(item)">{{item.text}}</span>
                <input *ngIf="item==editItem" type="text" [(ngModel)]="item.text" (keydown)="editorKeyDown($event)" [iuiFocus]="editorFocused" (focus)="selectContent($event)" (blur)="editorLostFocus()" />
                <div class="trw-add-dynamic-toolbar" *ngIf="item==hoverItem">
                    <span class="trw-add-dynamic-item-button trw-add-dynamic-item-button-delete" (click)="deleteItem(item)" [iuiTooltip]="{ appRef: applicationRef, title: 'Delete' }"></span>
                    <span class="trw-add-dynamic-item-button trw-add-dynamic-item-button-add-child" (click)="addChild(item)" [iuiTooltip]="{ appRef: applicationRef, title: 'Add Child' }"></span>
                    <span class="trw-add-dynamic-item-button trw-add-dynamic-item-button-add-root" (click)="addRoot()" [iuiTooltip]="{ appRef: applicationRef, title: 'Add Root' }"></span>
                </div>
            </div>
        </ng-template>
    </iui-treeview>
</div>
                            
/*
* sample-styles.css
*/ 

.trw-add-dynamic
{
    width: 350px;
    height: 300px;
}
.trw-add-dynamic .iui-treeitem-content
{
    margin: 1px 0 !important;
    padding: 5px !important;
}
.trw-add-dynamic-toolbar
{
    display: inline-block;
    position: absolute;
    right: 0;
    top: 7px;
    padding-left: 5px;
}
.trw-add-dynamic-item-button
{
    background-image: url(app/integralui/resources/icons.png);
    background-repeat: no-repeat;
    display: inline-block;
    overflow: hidden;
    padding: 0;
    margin: -1px 3px 0 3px;
    width: 16px;
    height: 16px;
    float: right;
    opacity: 0.5;
}
.trw-add-dynamic-item-button:hover
{
    opacity: 1;
}
.trw-add-dynamic-item-button-add-root
{
    background-position: -80px 0;
}
.trw-add-dynamic-item-button-add-child
{
    background-position: -32px -112px;
}
.trw-add-dynamic-item-button-delete
{
    background-position: -160px -96px;
}
.trw-add-dynamic-item-content
{
    background: red;
    display: inline-block;
}
                            

In addition, each button has a tooltip attached, which gives more information about the button function. For this purpose, the IntegralUI Tooltip directive is used.

Depending on which button is clicked, a corresponding action will take place. When the Add Root or Add Child button is clicked, a new empty item is created and a text editor pops up where you can enter the item label. This will create and place the new item at appropriate place within the tree structure.

If the new item is placed at wrong position, you can remove it by clicking the Delete button or change its label by clicking on it and enter a new one.

Conclusion

In cases where you need to create the tree structure on the fly in Angular TreeView, you can use command buttons placed in the item templates. Each button can have a different action: add parent or child items, editing or deleting items dynamically, during run-time from within the component UI.

The TreeView component is part of IntegralUI Web.

Did you Like this Article?


Enter your e-mail address below and you will receive latest articles as well as news on upcoming events and special offers.