LIDOR SYSTEMS

Advanced User Interface Controls and Components

Overview of IntegralUI TreeView for Angular 2

Created: 23 August 2016

Updated: 20 December 2016

IntegralUI TreeView is a native Angular 2 component that displays tree hierarchy of items that can be reordered using advanced drag drop operations. You can load data on demand during run-time from local or remote data sources, and add custom HTML content in each tree item. In following sections, you can find details about various features available in the TreeView component.

TreeView component is part of IntegralUI Studio for Web
a suite of UI Components for development of web apps

Above demonstration shows a simple tree hierarchy, each item has an icon and an editable label. When item is hovered, a command button will appear on right side, which when clicked will open a text editor, where you can change the item label.

You can reorder items by click and drag over specific item. A dragging window will appear, stating the target item and position at which item can be dropped. During drag drop operations, you can also create a copy of an item by holding the SHIFT key. The dragging window will change its icon, showing a + sign next to position marker.

Furthermore, expanding and collapsing of items is animated using built-in animation.

How to Use IntegralUI TreeView in Angular 2

In order to use the TreeView component in your app, you need to do the following:

  • Place the TreeView using the iui-treeview tag name
  • Define the template that will be used to create tree items
  • Add custom HTML elements as item content
  • Connect the TreeView to your data source

Because tree hierarchy can contain items in many levels, instead of setting a tree in HTML, you can just set the template by which each item is created:

//

// main.ts file

//

 

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

 

const platform = platformBrowserDynamic();

platform.bootstrapModule(AppModule);

 

 

 

//

// app.module.ts file

//

 

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

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

import { IntegralUIModule } from './integralui/integralui.module';

 

@NgModule({

imports: [ BrowserModule, IntegralUIModule ],

declarations: [ AppComponent ],

bootstrap: [ AppComponent ]

})

export class AppModule { }

 

 

 

//

// app.component.ts file

//

 

import { Component, ViewEncapsulation } from '@angular/core';

 

@Component({

selector: 'iui-app',

templateUrl: 'app.template.html',

styleUrls: ['treeview-overview.css'],

encapsulation: ViewEncapsulation.None

})

export class AppComponent {

// An Array object that holds all item objects shown in TreeView

// It is set as a list of any custom objects, you can use any custom fields and data bind them with TreeView using its properties

public items: Array;

 

// Get a reference of application view

@ViewChild('application', {read: ViewContainerRef}) applicationRef: ViewContainerRef;

 

// Editor settings

private isEditActive: boolean = false;

private editItem = null;

private originalText: string = '';

private editorFocused: boolean = false;

private hoverItem = null;

 

// Initialize items in component constructor

constructor(){

this.items = [

{

id: 1,

text: "Favorites",

icon: "computer-icons favorites",

items: [

{ id: 11, pid: 1, text: "Desktop", icon: "computer-icons empty-doc" },

{ id: 12, pid: 1, text: "Downloads", icon: "computer-icons downloads" }

]

},

{

id: 2,

text: "Libraries",

icon: "computer-icons folder",

items: [

{

id: 21,

pid: 2,

text: "Documents",

icon: "computer-icons documents",

expanded: false,

items: [

{ id: 211, pid: 21, text: "My Documents", icon: "computer-icons empty-doc" },

{ id: 212, pid: 21, text: "Public Documents", icon: "computer-icons empty-doc" }

]

},

{ id: 22, pid: 2, text: "Music", icon: "computer-icons music" },

{ id: 23, pid: 2, text: "Pictures", icon: "computer-icons pictures" },

{ id: 24, pid: 2, text: "Videos", icon: "computer-icons videos" }

]

},

{

id: 3,

text: "Computer",

icon: "computer-icons pc",

expanded: false,

items: [

{ id: 31, pid: 3, text: "Local Disk (C:)", icon: "computer-icons disk" },

{ id: 32, pid: 3, text: "Storage (D:)", icon: "computer-icons disk" }

]

},

{ id: 4, text: "Network", icon: "computer-icons network" },

{ id: 5, text: "Recycle Bin", icon: "computer-icons recycle" }

];

}

 

showEditor(item){

this.originalText = item.text;

this.isEditActive = true;

this.editItem = item;

this.editorFocused = true;

}

 

closeEditor(){

this.editItem = null;

this.originalText = '';

this.editorFocused = false;

}

 

editorKeyDown(e){

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();

}

 

}

 

bootstrap(AppComponent);

//

// app.template.html file

//

 

<div #application>

<iui-treeview [items]="items" [appRef]="applicationRef" #treeview>

<template let-item>

<div (mouseenter)="hoverItem=item" (mouseleave)="hoverItem=null">

<span [ngClass]="item.icon"></span>

<span *ngIf="item!=editItem">{{item.text}}</span>

<input *ngIf="item==editItem" type="text" [(ngModel)]="item.text" (keydown)="editorKeyDown($event)" (blur)="editorLostFocus()" [iuiFocus]="editorFocused" onFocus="this.setSelectionRange(0, this.value.length)" />

<div class="toolbar" *ngIf="item==hoverItem">

<span class="item-button item-button-edit" (click)="showEditor(item)"></span>

</div>

</div>

</template>

</iui-treeview>

</div>

/*

treeview-overview.css file

*/

 

.iui-treeview

{

width: 350px;

height: 350px;

}

.computer-icons

{

background-image: url(../../resources/computer.png);

background-repeat: no-repeat;

display: inline-block;

overflow: hidden;

padding: 0 !important;

margin: 0 2px 0 0;

width: 24px;

height: 24px;

vertical-align: middle;

}

.empty

{

background-position: 0px 0px;

}

.folder

{

background-position: -24px 0px;

}

.downloads

{

background-position: -48px 0px;

}

.favorites

{

background-position: -72px 0px;

}

.documents

{

background-position: -96px 0px;

}

.pc

{

background-position: -120px 0px;

}

.videos

{

background-position: -144px 0px;

}

.music

{

background-position: -168px 0p;

}

.network

{

background-position: -192px 0px;

}

.recycle

{

background-position: -216px 0px;

}

.pictures

{

background-position: -240px 0px;

}

.empty-doc

{

background-position: -264px 0px;

}

.disk

{

background-position: -288px 0px;

}

.toolbar

{

display: inline-block;

position: absolute;

right: 0;

top: 7px;

padding-left: 5px;

}

.item-button

{

background-image: url(../../../resources/icons.png);

background-repeat: no-repeat;

display: inline-block;

float: right;

height: 16px;

margin: 3px 4px 0 4px;

opacity: 0.5;

overflow: hidden;

padding: 0;

width: 16px;

}

.item-button:hover

{

opacity: 1;

}

.item-button-edit

{

background-position: -128px -81px;

}

Note If you want to show some item with different content then other items, you can use the directive and set condition by which a different content will appear.

In this example, each item has an icon, label, editor (represented by input element) and a command button on the right side. The editor is only visible when the button is clicked. After editing is completed or cancelled, the editor will disappear.

<template let-item>

<div (mouseenter)="hoverItem=item" (mouseleave)="hoverItem=null">

<span [ngClass]="item.icon"></span>

<span *ngIf="item!=editItem">{{item.text}}</span>

<input *ngIf="item==editItem" type="text" [(ngModel)]="item.text" (keydown)="editorKeyDown($event)" (blur)="editorLostFocus()" [iuiFocus]="editorFocused" onFocus="this.setSelectionRange(0, this.value.length)" />

<div class="toolbar" *ngIf="item==hoverItem">

<span class="item-button item-button-edit" (click)="showEditor(item)"></span>

</div>

</div>

</template>

When you have a template ready, you need to link the data source with the TreeView using the items property. The data source can be any array in flat or tree format.

Supported Properties

All properties of the TreeView component can be set using a separate attribute that is linked to an object in your application scope or to a specified value.

Here is a list of available properties:

  • appRef - holds a reference to application view
  • controlStyle - specifies an object that holds names for custom CSS classes
  • dataFields - specifies an object that map the fields names from data source to the ones used by the TreeView
  • items - holds a reference to the list of items defined in your application component
  • selectedItem - an object that points to the currently selected item

To avoid using plain javascript manipulation of the DOM and because of the way Angular 2 is structured, in order to show a tooltip, context menu or any other popup window, a reference to the root application component is required. You can provide a value to appRef property by simply setting a variable to the root component, and then access it by calling the ViewChild with specified variable name.

// Get a reference of application view

@ViewChild('application', {read: ViewContainerRef}) applicationRef: ViewContainerRef;

<div #application>

<iui-treeview [items]="items" [appRef]="applicationRef">

</iui-treeview>

</div>

If you want to have a specified item selected initially, you can set the selectedItem property to point to the item object in your data source. You can also set whether an item will appear as collapsed initially, by specifying the expanded field value to false. By default all items are expanded.

Data Binding in TreeView

When you have a custom data source which may differ from internal data settings of the tree view, you can use data binding which will match the names of data fields in your data source with those used by the tree view.

By specifying the items property to point to your data object, along with dataFields property that holds an object that maps the names of fields in the data object, you can populate the TreeView using any kind of custom data source.

This feature is also usable when you need to load data on demand in the TreeView, from a remote data source.

Supported Events

When interacting with the TreeView component, depending on the action, a corresponding event is fired. For example adding an item will fire itemAdding and itemAdded events, expanding it will fire the beforeExpand and afterExpand events, selecting it will fire beforeSelect, afterSelect and selectionChanged events, etc.

Here is a list of available events:

  • afterCollapse - occurs after item is collapsed
  • afterExpand - occurs after item is expanded
  • afterSelect - occurs after item is selected
  • beforeCollapse - occurs before item is collapsed
  • beforeExpand - occurs before item is expanded
  • beforeSelect - occurs before item is selected
  • clear - occurs when all items are removed from the TreeView
  • dragDrop - occurs when item is dropped over target item or empty space
  • dragEnter - occurs when dragged item enters the TreeView space
  • dragLeave - occurs when dragged item leaves the TreeView space
  • dragOver - occurs when item is dragged
  • itemAdded - occurs when new item is added to the TreeView
  • itemAdding - occurs before item is added
  • itemClick - occurs when item header is clicked
  • itemDblClick - occurs when item header is double-clicked
  • itemRemoved - occurs when item is removed from the TreeView
  • itemRemoving - occurs before item is removed
  • selectionChanged - occurs when currently selected item has changed

By handling these events in your code, you can add custom actions that may alter the default behavior of the TreeView component. For example, by handling the dragOver event, you can exclude a specified item as a target during drag drop operation, by setting a condition.

How to Add/Remove Items Dynamically

In some cases, you may need to add new items or remove existing items in the TreeView during run-time. For this purpose, there are built-in methods available that allow you to change the structure of the TreeView:

//

// app.component.ts file

//

 

export class AppComponent {

// An Array object that holds all item objects shown in TreeView

private data: Array;

 

// Get a reference to the TreeView component using a variable set in HTML

@ViewChild('treeview') treeview: IntegralUITreeView;

 

// Initialize items in component constructor

constructor(){

this.data = [];

}

 

// Adds a new item to the end of the TreeView

addItem(){

this.treeview.addItem({ text: "Item " + (this.data.length+1).toString() });

}

 

// Fired whenever a new item is added to the TreeView

itemAddedEvent(e){

if (e.item)

console.log("itemAdded: " + e.item.text);

}

}

 

bootstrap(AppComponent);

//

// app.template.html file

//

 

<iui-treeview [items]="data" (itemAdded)="itemAddedEvent($event)" #treeview>

<template let-item>

{{item.text}}

</template>

</iui-treeview>

In above code, we are adding a new item with some items using the addItem method. To access this method, at first we need to get a reference to the TreeView component. In HTML we are adding the #treeview variable, which is used to locate the TreeView within your application component.

After we have a reference to the TreeView component, we can get access to all public methods available:

  • addItem - inserts a new item at the end of TreeView
  • clearItems - removes all items from the TreeView
  • collapse - collapses all or specified item
  • expand - expands all or specified item
  • findItemById - searches through tree hierarchy for an item that matches specified id
  • findItemByText - searches through tree hierarchy for an item that matches specified text
  • insertItemAfter - inserts a new item in a position after specified item
  • insertItemBefore - inserts a new item in a position before specified item
  • insertItemAt - inserts a new item at specified position
  • removeItem - removes the specified item from the TreeView
  • scrollPos - gets or sets the current scrolling position
  • toggle - changes between expanded and collapsed state for all or specified item

Advanced Drag and Drop Operations

TreeView component comes with advanced drag drop that allows you to reorder items in tree hierarchy by simply dragging one or multiple items from one place to another within the same or other tree views.

During this process, events are fired that can help you to add custom actions that may alter the default built-in drag drop functionality. In each event you can set up custom conditions that can prevent or allow drag drop in special cases, depending on your application requirements.

Whenever an item is dragged, a draggin window will appear showing the target item and position at which item can be dropped. There are four possible positions:

  • up arrow - states that item will be dropped above target item
  • arc arrow - states that item will be dropped as a child of target item
  • down arrow - states that item will be dropped below target item
  • down arrow with a line - states that item will be dropped at the end of tree hierarchy

By default, during drag and drop items are moved from their original position to a new one. In some cases, instead of moving you may need to create a copy of dragged items. Copy operation is already built-in, you only need to press and hold the SHIFT key, when item is dropped. The dragging window will change its icon showing a + sign. This states that copy of dragged item will drop at specified position.

How to Customize the TreeView Appearance

Each part of IntegralUI TreeView component is fully customizable. There are different CSS classes for each component part. Although changing the attributes of built-in classes is possible, you can completely override them using the controlStyle property.

The controlStyle property accpets an object that holds all or partial list of CSS class names that will override the default CSS class names. For each component part, a different CSS class governs its appearance. This allows you to specify a set of different CSS classes for each component part and alter the appearance of the TreeView in whole. In this way, you can make it more suitable for your application requirements.

Conclusion

IntegralUI TreeView component allows you to display items in a tree hierarchy and reorder them dynamically using advanced drag drop operations. You can populate the TreeView using custom data source, locally or remotely.

By default, each item contains an icon and a label, and when using templates you can add any custom HTML elements or Angular 2 components. With use of ngIf directive, you can have different items with different content.

Currently this component is in BETA. More advanced features are in work like: context menus, tooltips, sorting, filtering, custom themes, etc, which will be available as part of the initial release.

The TreeView component will be part of IntegralUI Studio for Web. Here you can check out different features of existing components.

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.