LIDOR SYSTEMS

Advanced User Interface Controls and Components

Load on Demand in TreeView for AngularJS

Created: 30 June 2014

Updated: 19 February 2015

When we have a large and deep tree strucutre containing manu items with child items which also contains additional child items, populating the TreeView may come with some drawbacks in performance. To avoid this we need to load data on demand and dynamiucally change the data in our TreeView.

In following sections we will give an example where treeview is populated only when a specified item is expanding. This will maintain, even increase the overall performance of the TreeView directive.

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

Similar: Load Data on Demand in TreeView for Angular 2

At first we need to create a JSON file with some sample data. We will use AJAX to load the content of this file into a sample array, which we will use to populate the TreeView with data on demand.

angular

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

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

$scope.treeName = 'sampleTree';

$scope.data = [];

 

var timer = $timeout(function(){

// Read data from a JSON file using $http methods

var dataSource = $http.get('sample-data.json');

if (dataSource){

dataSource.success(function(data){

sampleData = data;

 

// At first only populate the TreeView with root items

extractData();

});

dataSource.error(function(data){

alert("AJAX failed to Load Data");

});

}

 

$timeout.cancel(timer);

}, 100);

}]);

<!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-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="data" before-expand="onBeforeExpand(e)"></iui-treeview>

</div>

</body>

</html>

[

{ "id": "1", "text": "Dairy", "expanded": false, "hasChildren": true },

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

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

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

{ "id": "14", "pid": "1", "text": "Yogurt" },

{ "id": "2", "text": "Fruits", "expanded": false, "hasChildren": true },

{ "id": "21", "pid": "2", "text": "Berries", "expanded": false, "hasChildren": true },

{ "id": "211", "pid": "21", "text": "BlackBerries" },

{ "id": "212", "pid": "21", "text": "CranBerries" },

{ "id": "213", "pid": "21", "text": "StrawBerries" },

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

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

{ "id": "24", "pid": "2", "text": "Citrus Fruits", "expanded": false, "hasChildren": true },

{ "id": "241", "pid": "24", "text": "Oranges" },

{ "id": "242", "pid": "24", "text": "Lemons" },

{ "id": "25", "pid": "2", "text": "Melons" },

{ "id": "26", "pid": "2", "text": "Tropical Fruits", "expanded": false, "hasChildren": true },

{ "id": "261", "pid": "26", "text": "Avocados" },

{ "id": "262", "pid": "26", "text": "Bananas" },

{ "id": "263", "pid": "26", "text": "Dates" },

{ "id": "3", "text": "Grains" },

{ "id": "4", "text": "Meat", "expanded": false, "hasChildren": true },

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

{ "id": "42", "pid": "4", "text": "Lamb", "expanded": false, "hasChildren": true },

{ "id": "421", "pid": "42", "text": "Lamb Breast" },

{ "id": "422", "pid": "42", "text": "Lamb Leg" },

{ "id": "423", "pid": "42", "text": "Lamb Ribs" },

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

{ "id": "5", "text": "Sweets" },

{ "id": "6", "text": "Vegetables" },

{ "id": "7", "text": "Water" }

]

In our sample JSON data, we have set the hasChildren field to true for those items that have children. This will make sure that the expand box is shown, when children are not present yet.

Now that we have some data loaded, we will populate the TreeView with root items only. Whenever expand box is clicked, a loading process will take place and when finished a set of child items will be added to the expanding item.

var isThereChildItems = function(parentId){

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

if (sampleData[i].pid === parentId)

return true;

}

 

return false;

}

 

var getItem = function(index){

var item = {

id: sampleData[index].id,

pid: sampleData[index].pid,

text: sampleData[index].text,

expanded: sampleData[index].expanded,

hasChildren: sampleData[index].hasChildren

}

 

// In order to show the expand box, create a

// temporary item which will act as a child item

if (isThereChildItems(sampleData[index].id))

item.items = [{ text: "temp" }];

 

return item;

}

 

var extractData = function(){

// Extract only root items

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

if (sampleData[i].pid === undefined)

$scope.data.push(getItem(i));

}

 

// Update the TreeView layout and refresh its view

$treeService.updateLayout($scope.treeName);

}

In order to add data on demand whenever an item is expanding, we need to handle the beforeExpand event. We can do this either by using the events or before-expand attribute. In this example we are going to use the before-expand attribute, like this:

// Whenever item is expanding, add child items to the expanding item

var loadOnDemand = function(item){

var childItems = [];

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

if (sampleData[i].pid === item.id)

childItems.push(getItem(i));

}

 

item.items = childItems;

}

 

// Before item is expanded, call the loadOnDemand method

// which will populate the item with its child items

$scope.onBeforeExpand = function(e){

// If the content of item is already loaded, just expand it

if (e.item.items && e.item.items.length > 1)

return;

else {

// Change the appearance of expand box with an animated gif which will notify the user that loading is in process

$treeService.beginLoad($scope.treeName, e.item);

 

var loadTImer = $timeout(function(){

loadOnDemand(e.item);

 

// Update the TreeView layout and refresh its view

$treeService.updateLayout($scope.treeName);

 

// Remove the loading icon and restore the default appearance of the expand box

$treeService.endLoad($scope.treeName, e.item);

}, 1000);

 

// Remove the temporary item

if (e.item.items)

e.item.items.splice(0, 1);

}

}

<iui-treeview name="{{treeName}}" items="data" before-expand="onBeforeExpand(e)"></iui-treeview>

As shown in above code, when item starts to expand the loadOnDemand method is called where only child items for that specific item are retrieved from the sample data. Then, the specified item collection of child items is replaced by this array. In this way you can change the content of specified item on the fly, reloading it with new data when it is required.

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.