Drag and Drop from DataGrid or AdvancedDataGrid to Tree
Line Break
Author: Arjan (47 Articles) - Author Website
Arjan is a SAP Consultant specialized in ABAP and Front End development techniques like Web Dynpro, Adobe Interactive Forms, Flex and AIR. In his free time he likes to create examples for Flex-Blog and other applications using Flex, AIR and PHP. Other hobbies are movies and music. He is also the co-owner of Flex-Blog.com.
One of the coolest things in Flex is the ability to create Drag and Drop operations very easily. For List base controls like the List and DataGrid / AdvancedDataGrid, it works out of the box, just set the dragEnabled property of the source and the dropEnabled property of the other and it’s already working. Dragging and Dropping to a Tree however, does not work by simply setting the dropEnabled property. The following example shows you how you can drag items from a DataGrid / AdvancedDataGrid to a Tree.
First let’s create two dataproviders, one for the DataGrid/AdvancedDataGrid and one for the Tree:
1 2 3 4 5 6 7 8 9 10 11 12 13 | [Bindable] private var collection1:ArrayCollection; [Bindable] private var collection2:XML = <node name="Root"> <node name="Node One"> <item name="Item One"/> <item name="Item Two"/> </node> <node name="Node Two"> <item name="Item Three"/> </node> </node>; |
So the XML typed dataprovider for the Tree already contains data, lets fill the dataprovider for the DataGrid/AdvancedDataGrid in a method that’s called upon initialization.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | private function init():void { var obj:Object; collection1 = new ArrayCollection(); obj = new Object(); obj.name = "Item Four"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Five"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Six"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Seven"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Eight"; collection1.addItem(obj); // open all items in Tree control this.validateNow(); tree.expandChildrenOf(collection2, true); } |
Now add the Component we are going to work with, the DataGrid (or AdvancedDataGrid) and the Tree:
DataGrid:
1 2 3 4 5 6 7 8 | <mx:DataGrid dragComplete="doDragComplete(event)" id="grid" width="50%" height="100%" dataProvider="{collection1}" dragEnabled="true" dragMoveEnabled="true"> <mx:columns> <mx:DataGridColumn headerText="Name" dataField="name"/> </mx:columns> </mx:DataGrid> |
Tree:
1 2 3 4 5 6 7 8 | <mx:Tree id="tree" width="50%" height="100%" dataProvider="{collection2}" dropEnabled="true" labelField="@name" dragOver="doDragOver(event)" dragDrop="doDragDrop(event)" dragEnter="doDragEnter(event)" dragExit="doDragExit(event)"/> |
Notice the following about the DataGrid:
- The DataGrid has dragEnabled set to true, this will allow the user to drag an item out of the DataGrid.
- The DataGrid has dragMoveEnabled set to true. When dragMoveEnabled is set to true, the Flex framework will automatically remove the dragged items from the source when the drag & drop operation is complete.
- The DataGrid has an event handler on the dragComplete event. The dragComplete event is dispatched by the drag source when your drag & drop operation is finished.
Notice the following about the Tree:
- The Tree has dropEnabled set to true.
- It has an event handler for the dragEnter event, dragEnter is dispatched when a drag operation enters the component (the Tree in this case).
- It has an event handler for the dragOver event. This is needed to tell the Flex framework to stop doing default drag & drop behaviour.
- It has an event handler for the dragDrop event. This is needed to handle the drop, dispatched when the user releases the Mouse cursor.
- It has an event handler for the dragExit event. This is dispatched when the Mouse cursor exits the component (Tree) while in a drag & drop procedure.
Ok now the fun part, implementing the functions. Most of them are simple, add the following four functions to your script area:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | private function doDragEnter(event:DragEvent):void { // Cancel default behaviour event.preventDefault(); // Tell the DragManager that the Tree will accent the DragDrop DragManager.acceptDragDrop(Tree(event.target)); // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.showDropFeedback(event); } private function doDragOver(event:DragEvent):void { // Show the default "drop line" in the Tree control tree.showDropFeedback(event); // Cancel default behavious event.preventDefault(); } private function doDragExit(event:DragEvent):void { // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.hideDropFeedback(event); } private function doDragComplete(event:DragEvent):void { // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.hideDropFeedback(event); } |
Now we can implement the final function that is going handle the drop for us. Add the following function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | private function doDragDrop(event:DragEvent):void { var item:XML; // cancel default event.preventDefault(); // get the drag format (its always items in our case // when you are dragging FROM a Tree its treeItems var draggedFormat:String = event.dragSource.formats[0]; // Get the dragged items var draggedItems:Array = event.dragSource.dataForFormat(draggedFormat) as Array; // Calculate the index in the Tree where the items were dropped var dropIndex:int = tree.calculateDropIndex(event); // Set the selected index of the Tree to the dropIndex tree.selectedIndex = dropIndex; // Check if we are dropping on a node // Add each dragged item to the Tree by apppending it // as a child of the selected node in the Tree. for each( var object:Object in draggedItems ) { // create item item = <item></item>; // set the name item.@name = object.name; // use appendChild to add the item. // (if selected item is an item then append to parent) if( (tree.selectedItem as XML).name() == "node") { (tree.selectedItem as XML).appendChild(item); } else{ (tree.selectedItem as XML).parent().appendChild(item); } } } |
That’s it you’re already done. You’re now able to drag items from Lists, DataGrids and such to a Tree. It’s pretty cool. Check out working example below follwed by the complete source code at the bottom of this post.
NOTE: This example is done in Flash Builder Beta and uses Flex 4. If you need this for Flex 3, just leave a comment and I will add the source for Flex 3.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" initialize="init()" xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768" viewSourceURL="srcview/index.html"> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ import mx.collections.ArrayCollection; import mx.controls.DataGrid; import mx.events.DragEvent; import mx.managers.DragManager; [Bindable] private var collection1:ArrayCollection; [Bindable] private var collection2:XML = <node name="Root"> <node name="Node One"> <item name="Item One"/> <item name="Item Two"/> </node> <node name="Node Two"> <item name="Item Three"/> </node> </node>; private function init():void { var obj:Object; collection1 = new ArrayCollection(); obj = new Object(); obj.name = "Item Four"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Five"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Six"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Seven"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Eight"; collection1.addItem(obj); // open all items in Tree control this.validateNow(); tree.expandChildrenOf(collection2, true); } private function doDragDrop(event:DragEvent):void { var item:XML; // cancel default event.preventDefault(); // get the drag format (its always items in our case // when you are dragging FROM a Tree its treeItems var draggedFormat:String = event.dragSource.formats[0]; // Get the dragged items var draggedItems:Array = event.dragSource.dataForFormat(draggedFormat) as Array; // Calculate the index in the Tree where the items were dropped var dropIndex:int = tree.calculateDropIndex(event); // Set the selected index of the Tree to the dropIndex tree.selectedIndex = dropIndex; // Check if we are dropping on a node // Add each dragged item to the Tree by apppending it // as a child of the selected node in the Tree. for each( var object:Object in draggedItems ) { // create item item = <item></item>; // set the name item.@name = object.name; // use appendChild to add the item. // (if selected item is an item then append to parent) if( (tree.selectedItem as XML).name() == "node") { (tree.selectedItem as XML).appendChild(item); } else{ (tree.selectedItem as XML).parent().appendChild(item); } } } private function doDragEnter(event:DragEvent):void { // Cancel default behaviour event.preventDefault(); // Tell the DragManager that the Tree will accent the DragDrop DragManager.acceptDragDrop( Tree(event.target) ); // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.showDropFeedback(event); } private function doDragOver(event:DragEvent):void { // Show the default "drop line" in the Tree control tree.showDropFeedback(event); // Cancel default behavious event.preventDefault(); } private function doDragExit(event:DragEvent):void { // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.hideDropFeedback(event); } private function doDragComplete(event:DragEvent):void { // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.hideDropFeedback(event); } ]]> </fx:Script> <s:HGroup width="400" height="250" paddingLeft="5" paddingTop="5"> <mx:DataGrid dragComplete="doDragComplete(event)" id="grid" width="50%" height="100%" dataProvider="{collection1}" dragEnabled="true" dragMoveEnabled="true"> <mx:columns> <mx:DataGridColumn headerText="Name" dataField="name"/> </mx:columns> </mx:DataGrid> <mx:Tree id="tree" width="50%" height="100%" dataProvider="{collection2}" dropEnabled="true" labelField="@name" dragOver="doDragOver(event)" dragDrop="doDragDrop(event)" dragEnter="doDragEnter(event)" dragExit="doDragExit(event)"/> </s:HGroup> </s:Application> |
Reuested in comment: The code for Flex 3, just a few changes to make it work.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()"> <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; import mx.controls.DataGrid; import mx.events.DragEvent; import mx.managers.DragManager; [Bindable] private var collection1:ArrayCollection; [Bindable] private var collection2:XML = <node name="Root"> <node name="Node One"> <item name="Item One"/> <item name="Item Two"/> </node> <node name="Node Two"> <item name="Item Three"/> </node> </node>; private function init():void { var obj:Object; collection1 = new ArrayCollection(); obj = new Object(); obj.name = "Item Four"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Five"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Six"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Seven"; collection1.addItem(obj); obj = new Object(); obj.name = "Item Eight"; collection1.addItem(obj); // open all items in Tree control this.validateNow(); tree.expandChildrenOf(collection2, true); } private function doDragDrop(event:DragEvent):void { var item:XML; // cancel default event.preventDefault(); // get the drag format (its always items in our case // when you are dragging FROM a Tree its treeItems var draggedFormat:String = event.dragSource.formats[0]; // Get the dragged items var draggedItems:Array = event.dragSource.dataForFormat(draggedFormat) as Array; // Calculate the index in the Tree where the items were dropped var dropIndex:int = tree.calculateDropIndex(event); // Set the selected index of the Tree to the dropIndex tree.selectedIndex = dropIndex; // Check if we are dropping on a node // Add each dragged item to the Tree by apppending it // as a child of the selected node in the Tree. for each( var object:Object in draggedItems ) { // create item item = <item></item>; // set the name item.@name = object.name; // use appendChild to add the item. // (if selected item is an item then append to parent) if( (tree.selectedItem as XML).name() == "node") { (tree.selectedItem as XML).appendChild(item); } else{ (tree.selectedItem as XML).parent().appendChild(item); } } } private function doDragEnter(event:DragEvent):void { // Cancel default behaviour event.preventDefault(); // Tell the DragManager that the Tree will accent the DragDrop DragManager.acceptDragDrop( Tree(event.target) ); // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.showDropFeedback(event); } private function doDragOver(event:DragEvent):void { // Show the default "drop line" in the Tree control tree.showDropFeedback(event); // Cancel default behavious event.preventDefault(); } private function doDragExit(event:DragEvent):void { // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.hideDropFeedback(event); } private function doDragComplete(event:DragEvent):void { // hide the "drop line" that is shown in Tree control // when dropping in a Tree tree.hideDropFeedback(event); } ]]> </mx:Script> <mx:HBox width="400" height="250" paddingLeft="5" paddingTop="5"> <mx:DataGrid dragComplete="doDragComplete(event)" id="grid" width="50%" height="100%" dataProvider="{collection1}" dragEnabled="true" dragMoveEnabled="true"> <mx:columns> <mx:DataGridColumn headerText="Name" dataField="name"/> </mx:columns> </mx:DataGrid> <mx:Tree id="tree" width="50%" height="100%" dataProvider="{collection2}" dropEnabled="true" labelField="@name" dragOver="doDragOver(event)" dragDrop="doDragDrop(event)" dragEnter="doDragEnter(event)" dragExit="doDragExit(event)"/> </mx:HBox> </mx:Application> |
Related posts:
- Data Dependant Tree Icon with Tree in AdvancedDataGrid with iconFunction
- Tree in Advanced DataGrid Example
- Change open and close icons on Flex Tree
- Style AdvancedDataGrid depending on data example
- Style Flex Tree Label Example
Comments
20 Responses to “Drag and Drop from DataGrid or AdvancedDataGrid to Tree”



(
Hi,
Drag and Drop from Advance Data Grid control. There is inbuilt tree structure in Advance Data Grid. So, i have to use that. Drag and Drop within the parent1 or child1,2…to restrict to another parent2 or child1,2…. How to do this in Flex 3.0.
Thanks & Regards,
–Sunitha Shali.
Can you explain to me in more detail what you want to do? Do you want to drag and drop inside the Tree structure in the AdvancedDataGrid or from another component?
Regards,
Arjan Nieuwenhuizen
Can u show me the code for Flex3 I really need it for my project
Flex 3 code is added at the bottom of the post.
Regards,
Arjan
Thank you very Flex 3 code, I have question when I move record form Datagridto tree. if my algorithm not allow some record move to tree but UI record have already gone from Datagrid when complete drag drop, How can I prevent this case happen
(I think) You have to program your own logic in the dragDrop event handler. There you can check if the item can be added or not. If not, just don’t add the item to the Tree and add it to the drag source (in this case, the datagrid) again.
Hope this helps.
Regards,
Arjan
Thanks for the flex 3 source!
There is a bug in the code: When I drop a list item under the closed tree item, the list item landed in the next tree item.
Peter
This was very helpfull, thank you!
That is awesome thank you!
I actually used this for dragging items from a dataGrid to a PieChart.
I was getting so frustrated because the drop method was never firing – even though the dragEnter and dragOver methods were.
The reason being is that even though I was firing preventDefault() in the dragEnter event, I was failing to do it in the dragOver event — un-be-freaking-livable!
Thanks again!
-Andrew
Thank you very much. Your code helped me.
Hello,
If I wrap the tree in the Panel. How can I set the related events? I should apply in the tree directly or in the Panel. My project is using AIR
Use the Tree, whether you wrap in in a Panel or not doesn’t make a difference. Its the Tree events you should react to.
Hope this helps
Arjan
Hi,
thanks for this example, it is really helpful. Is it possible also to copy the list-items instead of moving it into the tree? Copying the items would be exactly what I need.
Thanks a lot and all the best!
Max
Hi Max,
This is pretty easy to do. Change the dragMoveEnabled property to false like this:
2
3
4
5
6
7
8
id="grid" width="50%" height="100%"
dataProvider="{collection1}" dragEnabled="true"
dragMoveEnabled="false">
<mx:columns>
<mx:DataGridColumn headerText="Name" dataField="name"/>
</mx:columns>
</mx:DataGrid>
Note: dragMoveEnabled=”false”
That should do the trick.
Gr,
Arjan
drag and drop the item render (container ) in the same Advanced Dat grid .
it working fine .
But if the parent has no child , then it throws error like atleaset it must one sort filed
How to solve the issue..
I would like to do drag and drop inside the Tree structure(aka Tree column) in the AdvancedDataGrid (flex 3.0 ) is this possible to achieve?
thx
I figure out how can be done DND inside the Tree structure, to achieve DND within ADG Tree Column only, you should use custom render for a column.
thx
Pls suggest how to put an custom render for advancedatagridcolumn where is has Hierarchical data .
I think you can find your answer about custom ItemRenderer here:
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7bf2.html
great, the source pease