Drag and Drop from DataGrid or AdvancedDataGrid to Tree
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:
- Tree in Advanced DataGrid Example
- Style AdvancedDataGrid depending on data example
- Change open and close icons on Flex Tree
- Style Flex Tree Label Example
- Progressbar in Datagrid Example
Comments
6 Responses to “Drag and Drop from DataGrid or AdvancedDataGrid to Tree”
Got something to say?


(




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