LIDOR SYSTEMS

Advanced User Interface Controls and Components

TreeView like Toolbox in AngularJS

Created: 22 December 2015

Usually visual representation of tree hierarchy in Angular TreeView directive is created by shifting the child items to the right with small indentation relative to its parent. By removing this indentation, you can create a toolbox like tree view, where tree hierarchy will appear as flat list.

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

In above demonstration, we have a TreeView that appears like an Accordion. Root items behave like group headers and their content is a list of child items.

Note Although in this example we have only a one level tree hierarchy, you can add child items to the child items. All will be aligned with zero indentation.

How to Remove Indentation from Angular TreeView

In order to remove the indentation of tree items, we will use the indent property. This property by default is set to 15, which determines how many pixels the child item is shifted in relation to its immediate parent.

<!DOCTYPE html>

<html>

<head>

<link rel="stylesheet" href="css/integralui.css" />

<link rel="stylesheet" href="css/integralui.treeview.css" />

<link rel="stylesheet" href="css/themes/theme-flat-blue.css" />

<script type="text/javascript" src="external/angular.min.js"></script>

<script type="text/javascript" src="js/angular.integralui.min.js"></script>

<script type="text/javascript" src="js/angular.integralui.lists.min.js"></script>

<script type="text/javascript" src="js/angular.integralui.treeview.min.js"></script>

</head>

<body>

<div ng-app="appModule" ng-controller="appCtrl">

<iui-treeview name="{{treeName}}" items="items" indent="0" before-select="onBeforeSelect(e)" after-select="onAfterSelect(e)" item-click="onItemClick(e)"></iui-treeview>

</div>

</body>

</html>

By setting this property value to 0, all items in the Angular TreeView will appear on the same line, as they are root items.

Create TreeView to Appear as Toolbox

Next, we need to distinguish the root items from the child items by modifying their styles. In our example, root items will behave as blocks, and will appear differently than their children. This is accomplished by changing default CSS styles:

/* TreeView Parent Item Settings */

.iui-treeview-item

{

background: #e5e5e5;

border: thin solid #ababab;

margin: 1px 0;

padding: 1px 3px;

}

.iui-treeview-item-selected, .group-item

{

background: #c5c5c5;

border-color: #a1a1a1;

}

 

/* TreeView Child Item Settings */

.iui-treeview-item-child

{

background: transparent;

border: thin solid transparent;

font-weight: normal;

}

.iui-treeview-item-child-hovered

{

background: #f1f1f1;

border: thin solid #e5e5e5;

}

.iui-treeview-item-child-selected

{

background: transparent;

border-color: transparent;

}

.iui-treeview-item-child-content-selected

{

color: #c60d0d;

font-weight: bold;

}

 

/* TreeView Other Settings */

.iui-treeview-item-hovered

{

background: #f5f5f5;

border: thin solid #ababab;

margin: 1px 0;

}

.iui-treeview-item-content

{

background: transparent;

border-color: transparent;

}

.iui-treeview-item-content-selected, .group-item-content

{

color: black;

font-weight: bold;

}

 

/* TreeView ExpandBox Settings */

.iui-treeview-expand-box-open

{

background: url(../../../resources/icons.png) no-repeat -80px 0;

}

.iui-treeview-expand-box-close

{

background: url(../../../resources/icons.png) no-repeat -96px 0;

}

Each part of Angular TreeView directive has a CSS class which specifies their appearance. In case where some tree items will behave and appear differently than others (like in our example), we need to create custom CSS classes and apply them to specified items.

Here we have a set for CSS classes for parent and another set for child items. All these classes are applied through code.

angular

.module("appModule", ["integralui"])

.controller("appCtrl", ["$scope", "$timeout", "IntegralUITreeViewService", function($scope, $timeout, $treeService){

// A unique indentifer of the TreeView directive

$scope.treeName = "treeSample";

 

// An object that holds the names of CSS classes for parent items

var parentItemStyle = {

general: {

normal: 'group-item',

hovered: 'group-item'

},

content: {

normal: 'group-item-content',

hovered: 'group-item-content'

}

}

 

// An object that holds the names of CSS classes for child items

var childItemStyle = {

general: {

normal: 'iui-treeview-item-child',

hovered: 'iui-treeview-item-child-hovered',

selected: 'iui-treeview-item-child-selected'

},

content: {

selected: 'iui-treeview-item-child-content-selected'

}

}

 

// Data used to populate the TreeView

$scope.items = [

{

id: 1,

text: "Common Controls",

expanded: false,

items: [

{ id: 11, pid: 1, text: "Button" },

{ id: 12, pid: 1, text: "CheckBox" },

{ id: 13, pid: 1, text: "ComboBox" },

{ id: 14, pid: 1, text: "DateTime Picker" },

{ id: 15, pid: 1, text: "Label" },

{ id: 16, pid: 1, text: "ProgressBar" },

{ id: 17, pid: 1, text: "TextBox" }

]

},

{

id: 2,

text: "Containers",

items: [

{ id: 21, pid: 2, text: "GroupBox" },

{ id: 22, pid: 2, text: "Panel" },

{ id: 23, pid: 2, text: "SplitContainer" },

{ id: 24, pid: 2, text: "TabControl" }

]

},

{

id: 3,

text: "Menus & Toolbars",

items: [

{ id: 31, pid: 3, text: "ContextMenu" },

{ id: 32, pid: 3, text: "Menu" },

{ id: 33, pid: 3, text: "ToolStrip" }

]

},

{

id: 4,

text: "Data",

expanded: false,

items: [

{ id: 41, pid: 4, text: "DataGrid" },

{ id: 42, pid: 4, text: "DataSet" },

{ id: 43, pid: 4, text: "ReportViewer" }

]

},

{

id: 5,

text: "Dialogs",

expanded: false,

items: [

{ id: 51, pid: 5, text: "ColorDialog" },

{ id: 52, pid: 5, text: "FontDialog" }

]

},

{

id: 6,

text: "Printing",

expanded: false,

items: [

{ id: 61, pid: 6, text: "PrintDialog" },

{ id: 62, pid: 6, text: "PrintDocument" }

]

},

{

id: 7,

text: "IntegralUI",

items: [

{ id: 71, pid: 7, text: "Accordion" },

{ id: 72, pid: 7, text: "CheckBox" },

{ id: 73, pid: 7, text: "ComboBox" },

{ id: 74, pid: 7, text: "ContextMenu" },

{ id: 75, pid: 7, text: "Menu" },

{ id: 76, pid: 7, text: "SlideBar" },

{ id: 77, pid: 7, text: "TabStrip" },

{ id: 78, pid: 7, text: "TreeGrid" },

{ id: 79, pid: 7, text: "TreeView" }

]

}

];

 

var initTimer = $timeout(function(){

// Retrive a flat list of tree hierarchy

var list = $treeService.getFlatList($scope.treeName, true);

if (list && list.length > 0){

// Cycle through all items and set a custom style to each child item

// Skip the root items, they will use default CSS classes

for (var i = 0; i < list.length; i++){

if (list[i].pid)

list[i].style = childItemStyle;

}

}

 

// Select the item with label set to 'Menu'

$treeService.selectedItem($scope.treeName, $scope.items[2].items[1]);

 

$timeout.cancel(initTimer);

}, 1);

}]);

As a result, we have created a TreeView that appears like Visual Studio Toolbox.

Open Root Tree Items on Click

Now only remains to make sure root items will expand on click, even if the click is made outside their label space.

// Handler for itemClick event that make sure parent item is expanded or collapsed even if it is clicked outside its label

$scope.onItemClick = function(e){

var item = $treeService.getItemAt($scope.treeName, e.mousePos);

if (item){

// Update the value of suppressCallback variable to make sure the appearance of root item is not altered when item is selected

suppressCallback = true;

 

// Expand/Collapse the clicked item and select it

$treeService.toggle($scope.treeName, item);

$treeService.selectedItem($scope.treeName, item);

 

// If it is a child item, update the appearance of its parent

if (item.pid){

var parentItem = $treeService.getItemParent($scope.treeName, item);

if (parentItem){

parentItem.style = parentItemStyle;

currentGroupItem = parentItem;

}

 

// Update the TreeView appearance by calling the refresh method

$treeService.refresh($scope.treeName, parentItem);

}

else

currentGroupItem = item;

 

// Reset the suppressCallback value

suppressCallback = false;

}

}

To find which item is clicked, we are using the getItemAt method, which accepts the mouse position in page coordinates. The itemClick event carries the position of mouse cursor, so we can use it to find out which item is clicked. If there is an item, it will expand or collapse its content.

We are also handling the beforeSelect and afterSelect events, to make sure the appearance of parent items is updated whenever a child item is selected.

var currentGroupItem = null;

var suppressCallback = false;

 

// Handler for beforeSelect event that resets the appearance of parent items

$scope.onBeforeSelect = function(e){

if (currentGroupItem){

var parentItem = $treeService.getItemParent($scope.treeName, e.item);

if ((e.item.pid && currentGroupItem != parentItem) || (!e.item.pid && currentGroupItem != e.item)){

currentGroupItem.style = null;

$treeService.refresh($scope.treeName, currentGroupItem);

 

currentGroupItem = null;

}

}

}

 

// Handler for afterSelect event that changes the appearance of parent and child items whenever an item is selected

$scope.onAfterSelect = function(e){

if (!suppressCallback){

// If selected item is a child, update the appearance of its parent

if (e.item.pid){

var parentItem = $treeService.getItemParent($scope.treeName, e.item);

if (parentItem){

parentItem.style = parentItemStyle;

currentGroupItem = parentItem;

}

 

// Update the TreeView appearance by calling the refresh method

$treeService.refresh($scope.treeName, parentItem);

}

else

currentGroupItem = e.item;

}

}

Conclusion

By modification of existing CSS styles and creating new custom CSS classes, we have been able to create a toolbox like TreeView. In addition, small changes to the TreeView behavior was added using AngularJS code and handling few events. The result is a flat TreeView with zero indentation, which acts and behaves like a Visual Studio Toolbox.

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.