Dragging rows between two different Flex DataGrid controls

The following example shows how you can use the dragEnabled, dropEnabled, and dragMoveEnabled properties with the Flex DataGrid control to copy and move rows between different data grids.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/09/19/dragging-rows-between-two-different-flex-datagrid-controls/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="horizontal"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Array id="arr">
        <mx:Object colA="Item A.0" colB="Item B.0" colC="Item C.0" />
        <mx:Object colA="Item A.1" colB="Item B.1" colC="Item C.1" />
        <mx:Object colA="Item A.2" colB="Item B.2" colC="Item C.2" />
        <mx:Object colA="Item A.3" colB="Item B.3" colC="Item C.3" />
        <mx:Object colA="Item A.4" colB="Item B.4" colC="Item C.4" />
        <mx:Object colA="Item A.5" colB="Item B.5" colC="Item C.5" />
        <mx:Object colA="Item A.6" colB="Item B.6" colC="Item C.6" />
        <mx:Object colA="Item A.7" colB="Item B.7" colC="Item C.7" />
        <mx:Object colA="Item A.8" colB="Item B.8" colC="Item C.8" />
        <mx:Object colA="Item A.9" colB="Item B.9" colC="Item C.9" />
    </mx:Array>

    <mx:ApplicationControlBar dock="true">
        <mx:Form>
            <mx:FormItem label="DataGrid #1:"
                    direction="horizontal">
                <mx:CheckBox id="dg1_dragEnabled"
                        label="dragEnabled" />
                <mx:CheckBox id="dg1_dropEnabled"
                        label="dropEnabled" />
                <mx:CheckBox id="dg1_dragMoveEnabled"
                        label="dragMoveEnabled" />
            </mx:FormItem>
            <mx:FormItem label="DataGrid #2:"
                    direction="horizontal">
                <mx:CheckBox id="dg2_dragEnabled"
                        label="dragEnabled" />
                <mx:CheckBox id="dg2_dropEnabled"
                        label="dropEnabled" />
                <mx:CheckBox id="dg2_dragMoveEnabled"
                        label="dragMoveEnabled" />
            </mx:FormItem>
        </mx:Form>
    </mx:ApplicationControlBar>

    <mx:VBox width="50%">
        <mx:Label text="DataGrid #1" />
        <mx:DataGrid id="dataGrid1"
                width="100%"
                rowHeight="22"
                dataProvider="{arr}"
                dragEnabled="{dg1_dragEnabled.selected}"
                dragMoveEnabled="{dg1_dragMoveEnabled.selected}"
                dropEnabled="{dg1_dropEnabled.selected}"
                verticalScrollPolicy="on">
            <mx:columns>
                <mx:DataGridColumn dataField="colA"
                        headerText="Column A" />
                <mx:DataGridColumn dataField="colB"
                        headerText="Column B" />
                <mx:DataGridColumn dataField="colC"
                        headerText="Column C" />
            </mx:columns>
        </mx:DataGrid>
        <mx:Label text="{dataGrid1.dataProvider.length} items" />
    </mx:VBox>

    <mx:VBox width="50%">
        <mx:Label text="DataGrid #2" />
        <mx:DataGrid id="dataGrid2"
                width="100%"
                rowHeight="22"
                dataProvider="[]"
                dragEnabled="{dg2_dragEnabled.selected}"
                dragMoveEnabled="{dg2_dragMoveEnabled.selected}"
                dropEnabled="{dg2_dropEnabled.selected}"
                verticalScrollPolicy="on">
            <mx:columns>
                <mx:DataGridColumn dataField="colA"
                        headerText="Column A" />
                <mx:DataGridColumn dataField="colB"
                        headerText="Column B" />
                <mx:DataGridColumn dataField="colC"
                        headerText="Column C" />
            </mx:columns>
        </mx:DataGrid>
        <mx:Label text="{dataGrid2.dataProvider.length} items" />
    </mx:VBox>

</mx:Application>

View source is enabled in the following example.

42 thoughts on “Dragging rows between two different Flex DataGrid controls

  1. Hi Peter,
    I have a new problem I am hoping you can find solution to. I wanted to create a datagrid with some scrollable columns and some columns without scroll. So, I created two datagrids with a horizontal gap of -1 so that they look like single grid. The problem I had was that when i clicked on a row in first datagrid it did not highlight the row in 2nd datagrid. So I did :
    BindingUtils.bindProperty(dg,”selectedIndex”,dg1,”selectedIndex”);
    BindingUtils.bindProperty(dg1,”selectedIndex”,dg,”selectedIndex”);
    i.e binded the selected index of each datagrid with the other. It seemed to run fine when I had a normal flash player installed but when a friend of mine had a debug version of flash player installed it gave stackoverflow error which I figured was due to the recursion created by above two statements. Is there any other way to do it?

  2. I am trying to do the same thing “Dragging rows between two different Flex DataGrid controls” but in my case it is not dragging though. I have 2 buttons add and remove with which i want to achieve the same result.

    i have being working on it for almost 2 days not and havent been successful.
    any suggestions?

  3. hello, is it possible to drag onto a datagrid item, for example i have a datagrid with a list of all my playlists, and i would like to drag and drop a file from another datagrid into a playlist,

    drag and drop this music item onto the right playlist but not add it to the datagrid with saved playlists, just check onto wich item it has been dropped and add it to the right playlist file (xml)

    like you can do in iTunes actually.

    grtz thomas

  4. hey!
    awesome examples! please keep up the good work.
    i am basically a .net guy and a flex newbie. i was breaking my head over a scenario. i was playing around with the drag drop features in flex. i have two datagrids one is a list of all available items and another is a list of my favorite items. i’ve got the regular drag drop to work well. the only problem i’ve is in the case if there are saved favorites which needs to be displayed in the second grid.

    if we use two separate xmls – ‘all’ and ‘saved’ to bind to the two grids then you are basically working with two separate sets of data and hence when you drag drop between the lists duplicates are created.

    how can i get this to work? any help/hint will be much appreciated :)

  5. So I’m trying to allow a user to drag items from one list to the other. That’s not the problem. The problem that I’m having is preventing them from being able to hold down the Ctrl key to copy the items. Maybe there is something obvious that I’m missing but I have looked all over. The ListBase class is the class that handles the built in drag and drop features of Lists. It doesn’t appear that there is a mechanism to prevent the copy. I guesss I could override that function in my instance of the list… It seems like there should be an easier way!! Please help!
    Thanks.

  6. Nevermind. I got it… I just took my own advise and overrode.. ? overridded?… overrid? anyway… I did this…

    I created a new Component based off of the List class and added the code in the script tags below.

    Hope this helps someone.

  7. Let me try this one more time…

    Code between the script tags:

    import mx.events.DragEvent;
    import mx.managers.DragManager;
    override protected function dragDropHandler(event:DragEvent):void
    {
    	event.action = DragManager.MOVE;
    	DragManager.showFeedback(DragManager.MOVE);
    	super.dragDropHandler(event);
    }
    
  8. @Thomas

    The solution for that is calculateDropIndex()
    example to highlight the drag-over-item:

    private function dragOverHandler(event:DragEvent):void {
    	var grid:DataGrid = DataGrid(event.currentTarget);
    	var index:int = grid.calculateDropIndex(event);
    	if (index == grid.dataProvider.length) {
    		grid.selectedIndex = -1;
    		return;
    	}
    	grid.selectedIndex = index;
    }
    
  9. Hello!

    I an developing an application with a datagrid, which is populated dynamically as a result of a HTTPService request, creating the columns and inserting the rows. This request is triggered by a drop event from a list.
    My idea was to remove columns from the datagrid, causing the data (column + rows) to refresh, by dragging a column “out” of the datagrid, but i don’t know if such thing is possible… Can anyone help me? Thank you!

  10. Hi Peter,am new to flex world and i find ur examples extremely helpful… i tried drag and drop but i have to get things done using and button… two grids with the buttons. Havent found a solution yet

  11. Shalini,

    This is a little rough, but should work:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white">
    
        <mx:Script>
            <![CDATA[
                private function moveRight():void {
                    var item:Object = dataGrid1.selectedItem;
                    if (item) {
                        var idx:int = arrColl1.getItemIndex(item);
                        arrColl2.addItem(item);
                        arrColl1.removeItemAt(idx);
                    }
                }
    
                private function moveLeft():void {
                    var item:Object = dataGrid2.selectedItem;
                    if (item) {
                        var idx:int = arrColl2.getItemIndex(item);
                        arrColl1.addItem(item);
                        arrColl2.removeItemAt(idx);
                    }
                }
            ]]>
        </mx:Script>
    
        <mx:Array id="arr">
            <mx:Object label="One" />
            <mx:Object label="Two" />
            <mx:Object label="Three" />
            <mx:Object label="Four" />
            <mx:Object label="Five" />
        </mx:Array>
    
        <mx:ArrayCollection id="arrColl1" source="{arr}" />
        <mx:ArrayCollection id="arrColl2" />
    
        <mx:HBox>
            <mx:DataGrid id="dataGrid1"
                    dataProvider="{arrColl1}"
                    rowCount="5">
                <mx:columns>
                    <mx:DataGridColumn dataField="label" />
                </mx:columns>
            </mx:DataGrid>
            <mx:VBox height="100%" verticalAlign="middle">
                <mx:Button label="&gt;&gt;" click="moveRight();" />
                <mx:Button label="&lt;&lt;" click="moveLeft();" />
            </mx:VBox>
            <mx:DataGrid id="dataGrid2"
                    dataProvider="{arrColl2}"
                    rowCount="5">
                <mx:columns>
                    <mx:DataGridColumn dataField="label" />
                </mx:columns>
            </mx:DataGrid>
        </mx:HBox>
    
    </mx:Application>
    

    Peter

  12. Great examples, thanks for that.
    I have a query perhaps someone can help with:

    I have 2 list controls and am dragging from one to the other. This is all fine. The target list is configured to use an XMLList variable as it’s data provider.

    When the list only contains 1 dropped item, the dataprovider is EMPTY.

    When it contains > 1 item, the dataprovider contains the XML that I expect it would, namely the representation of the data that has been dropped.

    DataGrid shows the same issue.

    Any ideas?

    Thanks for any help,
    SG

  13. Hi,
    I’m looking for similar solution (dragging rows beetween two datagrids/lists) but based on native actionscript components (f.g. fl.controls.DataGrid)

    Is possible to use some components which supporting draggin events in native AS3?
    Have you got some?

    Thanks for any help

  14. To expand on Peter’s example (using buttons to move data from one list to another), you can do this with dynamic data. Note that in my code below, I actually have three lists, one on the left and two on the right (lists B and C), so I pass the list as a parameter, and I have a Left and Right button for list B (A to B, B to A) and another pair for list C (A to C, C to A).

    Also note that MoveOnlyList is the name of the component I created as in Dante’s example, so that items are never copied, always moved (my experience was that the destination list was the controller, so any list that received items had to be a MoveOnlyList).

    private function moveRight( destList:MoveOnlyList ):void {
        var item:Object = listOnTheLeft.selectedItem;
        if ( item ) {
            var acSource:ArrayCollection = ArrayCollection( listOnTheLeft.dataProvider );
            var idx:int = acSource.getItemIndex( item );
            var acDest:ArrayCollection;
            if ( destList.dataProvider == null ) {
                acDest = new ArrayCollection();
                destList.dataProvider = acDest;
            } else {
                acDest = ArrayCollection( destList.dataProvider );
            }
            acDest.addItem( item );
            acSource.removeItemAt( idx );
        }
    }
    
  15. I have a problem!
    I have a page in which I need to place two pairs of datagrids(total four) with one column in each datagrid.
    I need to drag an item from datagrid1 to datagrid2 ONLY and NOT to any other grid.
    Similarly from datagrid3 to datagrid4 ONLY.
    But when I tried, I can drag an item from datagrid1 to datagrid3, but interesting thing is that
    the data is not dropped into datagrid3 (instead a blank row is inserted), its getting lost from datagrid1.
    How to solve this issue?

  16. AK, your column data needs to be named the same in both datagrids that are utilizing the drag and drop data. The data will then show up instead of a blank row.

  17. @Dante
    – I wanted to express my gratitude as I also came across the problem of preventing users from making copies of the data while trying to reorder rows via the drag and drop feature. I tried what you had posted and it worked beautifully.

  18. I’ve been looking for this everywhere but can’t find it.. I’m really hopping you can help.

    I’m dragging new items to existing datagrid and creating new columns.

    On item drop I’d like to know which column of existing datagrid I’m droping on.

    I can easily determine row I’m droping in dragDrop event: var dropLoc:int = dropTarget.calculateDropIndex(event); but how do I determine column?

    Any help or reference will be greatly appreciated!

    1. I am looking for the same solution – knowing which column was dropped on. Any luck in finding a solution?

  19. That is something what i was looking for. But can it be done that one is a normal DG and the other one is an advanced DG, both having different columns?

  20. Jackson Barcellos,

    All the code is in the post above (there aren’t any other files needed).
    But I did recreate the project in Flex Builder and repost the source and it should all work now.

    Sorry about that,
    Peter

  21. Hi Peter,

    I have two advanceddatagrid(grid1, grid2), where each grid has two different hierarchial data model having grouped columns. Since this reason i placed preventDefault() method to handle drop events manually.

    Need to allow dragging grid1 data to grid2 with necessary data change. On dragging from grid1, am using mouseDown event to track which element being selected for dragging, on the other hand while the dropping, how to find where the element being dropped in second grid.

  22. Hi,
    I need help from you .
    I have a list which have the drop and drop functionality.
    How can i calculate the drop index of list
    I tried with list.calculateDropIndex(ev);
    but iam getting length of arrayColl not drop index.
    ex:
    I have 5 row in a list I am going to drag the 4th row into the I st row
    Now i need the droped item row index.
    how can i find throw bu coding

    if anybody know abt this let me know.
    Thanks and regards,
    Naresh

    1. Naresh,
      try using (event.relatedObject as List).lastDropIndex;
      i had the same problem as you, and the line above seems to do the trick.

  23. Hi, Excellent blog

    Do you know how to DISABLE the drag and drop in a one simple column of the AdvancedDataGrid? just one not entire

  24. Hi,

    In this example, is there a way you can avoid highlighting the list border when we drag both in source list and destination list(when we drag over it)?

    Thanks!

  25. Hi , here is a code that puts a datagrid value into a list , this is done pretty first time , so guys enjoy.

  26. <?xml version=”1.0″ encoding=”utf-8″?>
    <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”
    creationComplete=”initApp();”>

    <mx:Script>
    <![CDATA[

    import mx.events.DragEvent;
    import mx.managers.DragManager;
    import mx.core.DragSource;
    import mx.collections.IList;
    import mx.collections.ArrayCollection;
    import mx.controls.Alert;

    private function initApp():void {

    destDG.dataProvider = new ArrayCollection([
    {label:”First”, data:”1″},
    {label:”Second”, data:”2″},
    {label:”Third”, data:”3″},
    {label:”Fourth”, data:”4″},
    ]);

    srcList.dataProvider = new ArrayCollection([]);

    }

    private function dragDropHandler(event:DragEvent):void {
    if (event.dragSource.hasFormat(“items”))
    {
    // Explicitly handle the dragDrop event.
    event.preventDefault();

    // Since you are explicitly handling the dragDrop event,
    // call hideDropFeedback(event) to have the drop target
    // hide the drop indicator.
    // The drop indicator is created
    // automatically for the list controls by the built-in
    // event handler for the dragOver event.
    event.currentTarget.hideDropFeedback(event);

    // Get drop target.
    var dropTarget:List =
    List(event.currentTarget);

    var itemsArray:Array =
    event.dragSource.dataForFormat(‘items’) as Array;
    var tempItem:Object =
    { label: itemsArray[0].Fund,
    data: itemsArray[0].AMC,
    data: itemsArray[0].Risk_Rating
    };

    // Get the drop location in the destination.
    var dropLoc:int = dropTarget.calculateDropIndex(event);

    IList(dropTarget.dataProvider).addItemAt(tempItem, dropLoc);
    }
    }
    ]]>
    </mx:Script>

    <mx:HBox>
    <mx:List id=”srcList”
    dragEnabled=”true”
    dropEnabled=”true”
    dragDrop=”dragDropHandler(event);”/>

    <mx:DataGrid id=”destDG”
    dragEnabled=”true”
    dragMoveEnabled=”true”>
    <mx:columns>
    <mx:DataGridColumn dataField=”label”/>
    <mx:DataGridColumn dataField=”data”/>
    <mx:DataGridColumn dataField=”date”/>
    </mx:columns>
    </mx:DataGrid>

    </mx:HBox>

    <mx:Button id=”b1″
    label=”Reset”
    click=”initApp()”
    />

    </mx:Application>

  27. Hi Guys,

    How to pass details from one datagrid to another which is in another mxml component.

    Thanks in advance.

  28. Hi

    Just wondering if there is a way to achieve the same functionality, but in Flash CS4 or 5 using AS3 (and possibly AIR)?

    Thanks

    Shaun Thomson

Comments are closed.