LIDOR SYSTEMS

Advanced User Interface Controls and Components

Drag Drop Between TreeView and Tree Grid AngularJS

Created: 09 April 2015

Both TreeView and Tree Grid components for AngularJS support drag drop operations within their own space. Additonally, they also provide built-in functionality which allows you to easily drag & drop items from TreeView to Tree Grid and vice versa. The below demonstration shows how this work.

TreeView and Tree Grid directives are part of IntegralUI Studio for Web
a suite of UI Components for development of web apps

As it can be seen from above demonstration, when item from TreeView is dragged over the Tree Grid space, a tooltip will appear stating targeting row and position at which dragged item will be dropped. In this process when item is dropped, a row is automatically created using the data from the tree item.

Note The tooltip icon changes depending on drop position. It can be up, down or move in arrow, which will place the dragged item above, below or as a child of target item.

In similar way, when row from Tree Grid is dragged over TreeView space, a tooltip will appear stating the target item and the position at which dragged row will be dropped. When row is dropped, an item is created using only the row text, and cells that belong to the row are not displayed.

In both cases, all data is sustained, only in case of dropping a tree item, because there are no cells for item objects, they are internally created by the built-in functionality of the Tree Grid.

angular

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

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

$scope.treeName = "treeSample";

$scope.gridName = "gridSample";

$scope.itemIcon = "icons file";

 

$scope.treeData = [

{

id: 1,

text: "Item1",

icon: "icons folder",

items: [

{

id: 11,

pid: 1,

text: "Item11",

icon: "icons folder",

expanded: false,

items: [

{ id: 111, pid: 11, text: "Item111" },

{ id: 112, pid: 11, text: "Item112" }

]

},

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

]

},

{

id: 2,

text: "Item2",

icon: "icons folder",

expanded: false,

items: [

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

]

},

{

id: 3,

text: "Item3"

}

];

 

$scope.columns = [

{ headerText: "Header1", footerText: "Footer1", width: 150 },

{ headerText: "Header2", footerText: "Footer2", width: 120 },

{ headerText: "Header3", footerText: "Footer3" }

];

 

$scope.rows = [

{

id: 4,

text: "Item41",

icon: "icons folder",

cells: [{ text: "Item41" }, { text: "Item42" }, { text: "Item43" }],

rows: [

{

id: 41,

pid: 4,

text: "Item411",

cells: [{ text: "Item411" }, { text: "Item412" }, { text: "Item413" }]

},

{

id: 42,

pid: 4,

text: "Item421",

icon: "icons folder",

expanded: false,

cells: [{ text: "Item421" }, { text: "Item422" }, { text: "Item423" }],

rows: [

{

id: 421,

pid: 42,

text: "Item4211",

cells: [{ text: "Item4211" }, { text: "Item4212" }, { text: "Item4213" }]

}

]

}

]

},

{

id: 5,

text: "Item51",

icon: "icons folder",

cells: [{ text: "Item51" }, { text: "Item52" }, { text: "Item53" }],

rows: [

{

id: 51,

pid: 5,

text: "Item511",

cells: [{ text: "Item511" }, { text: "Item512" }, { text: "Item513" }]

}

]

}

];

}]);

<!DOCTYPE html>

<html>

<head>

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

<link rel="stylesheet" href="css/integralui.treegrid.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.treegrid.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="treeData" allow-drag="true" allow-drop="true" item-icon="itemIcon"><iui-treeview>

<iui-treegrid name="{{gridName}}" columns="columns" rows="rows" allow-drag="true" allow-drop="true" show-footer="false" row-icon="itemIcon"></iui-treegrid>

</div>

</body>

</html>

Handling Drag Drop Events to Change Item Icon

You may also notice from above demonstration during drag drop operations, that icon of parent items and rows changes. Depending on whether there are child objects the icon is changed to folder icon, if there are no chidren, icon changes to a file icon. This functionality is added in this sample code, by handling drag-drop and remove events for both components.

Related: Drag Drop Events with Custom Conditions in Tree Grid AngularJS

You can modify this in your code and add any custom functionality. By handling dragDrop event for example, you can set custom conditons and when they are met you can invoke a custom operation. In case of our example, we are adding code which changes the icon of parent of dragged object (item or row).

angular

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

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

$scope.treeDrop = function(e){

changeObjIcon(e.dragItem);

}

 

$scope.gridDrop = function(e){

changeObjIcon(e.dragRow);

}

 

var changeObjIcon = function(obj){

if (obj){

if ((obj.type == 'item' && obj.items && obj.items.length > 0) || (obj.type == 'row' && obj.rows && obj.rows.length > 0))

obj.icon = "icons folder";

else

obj.icon = "icons file";

 

// Update the icon for parent objects

var updateTimer = $timeout(function(){

var parent = getParent(obj);

changeObjIcon(parent);

 

$timeout.cancel(updateTimer);

}, 1);

}

}

 

// Get parent object of specified object (item or row)

var getParent = function(obj){

switch (obj.type){

case 'item':

return $treeService.getItemParent($scope.treeName, obj);

 

case 'row':

return $gridService.getRowParent($scope.gridName, obj);

}

 

return null;

}

}]);

<!DOCTYPE html>

<html>

<head>

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

<link rel="stylesheet" href="css/integralui.treegrid.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.treegrid.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="treeData" allow-drag="true" allow-drop="true" item-icon="itemIcon" drag-drop="treeDrop(e)" item-removing="objRemoving(e)" item-removed="objRemoved(e)"><iui-treeview>

<iui-treegrid name="{{gridName}}" columns="columns" rows="rows" allow-drag="true" allow-drop="true" show-footer="false" row-icon="itemIcon" drag-drop="gridDrop(e)" row-removing="objRemoving(e)" row-removed="objRemoved(e)"></iui-treegrid>

</div>

</body>

</html>

Each item or row object has an icon field which accepts a CSS class name. Because internally icons are represented by element, and as background we are using an image. The size and position of these icons is set in CSS class (see above CSS content).

Depending on whether specified item or row has children, a different icon is set. As you can see the changeObjIcon method has a recursion in place, this automatically updates the icon of all parents for specified object.

Note Because in AngularJS there is a small delay until data is created, we are using a $timeout service to make sure tree hierarchy si fully created.

Depending on object type, item or row, we are usign a different public method to retrieve the parent of dragged object. These methods are part of built-in service for TreeView and Tree Grid directives.

By handling dragDrop event we can update the appearance of target TreeView or Tree Grid. However, the appearance of source component will not be upadted by above code. For this purpose we need to handle the itemRemoving and itemRemoved events for TreeView and rowRemoving and rowRemoved events for Tree Grid.

var parentObj = null;

$scope.objRemoving = function(e){

parentObj = getParent(e.obj);

}

 

$scope.objRemoved = function(e){

changeObjIcon(parentObj);

}

When dragged object is moved from TreeView to Tree Grid and vice versa, the above event handlers wil be called. During this process because the parent of object will change after drop operation is completed, we need to retrieve the original parent object. This is done in objRemoving function. Then we can use this parent object to update the icons for source component.

As a result we have a cully funxctional drag drop operation between TreeView and Tree Grid directives, with some custom functionality.

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.