Posted by The Fattest on 07/17/2008

9 comments
Skill

Simple Flex Drag and Drop

Posted in:

Today I am going to run through a smallish tutorial on creating and using drag and drop in Flex using the DragManager class, which is a utility provided to make drag and drop easy. I should also mention, right off the bat, that some things like lists already have various drag and drop features built in. I however will be showing an example that is useful for any custom drag jobs you might need to do.

The application below shows the functionality that I will be building today. It is a very simple demo that has a few games up at the top that can be added to your shopping cart by dragging them down into the basket area. Once dropped into the "basket" they will show up in the shopping cart list. The interface is simple and the code is simple - and you can grab that code using this link: Drag and Drop Source Code.

Get Adobe Flash player

Like most Flex tutorials I am going to quickly take a glance at the user interface which includes a couple canvases, labels, and a datagrid. The most important pieces are the images of the games and the basket drop canvas. As seen below, all the images have the MouseDown event hooked up and the basket canvas has the dragEnter and dragDrop events setup. The handlers for these events are going to do all the work to make the drag and drop to run nicely.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="absolute" width="374" height="406">
  <mx:Label x="0" y="210" text="Games" width="118" height="42"
     fontSize="28" color="#818181"/>
  <mx:Image name="Bioshock" x="2" y="2" source="{bioshock_icon}"
     mouseDown="doDrag(event)" />
  <mx:Image name="Crysis" x="120" y="2" source="{crysis_icon}"
     mouseDown="doDrag(event)" />
  <mx:Image name="Halo" x="240" y="2" source="{halo_icon}"
     mouseDown="doDrag(event)" />
  <mx:Image name="Neverwinter Nights" x="50" y="110"
     source="{neverwinter_icon}" mouseDown="doDrag(event)" />
  <mx:Image name="World of Warcraft" x="200" y="110"
     source="{wow_icon}" mouseDown="doDrag(event)" />
  <mx:Canvas x="0" y="255" width="174" height="151"
     borderStyle="solid" backgroundColor="#12976A"
     dragEnter="dragAccept(event)" dragDrop="dragDrop(event)">
    <mx:Label x="0" y="0" text="Basket" width="118" height="42"
       fontSize="28" color="#FFFFFF"/>
  </mx:Canvas>
  <mx:DataGrid dataProvider="{cartContents}" x="173" y="255"
     width="201" height="151">
    <mx:columns>
      <mx:DataGridColumn headerText="Name" dataField="name"/>
      <mx:DataGridColumn headerText="Quantity" dataField="num" width="65"/>
    </mx:columns>
  </mx:DataGrid>
  <mx:Label x="272" y="235" text="Shopping Cart" color="#3A3A3A"
     fontWeight="bold" fontSize="12"/>
</mx:Application>

One of the first things you might notice in the above code is the references to the icons as the source for the images. Well we are going to embed these into the application. To do this we are going to add a Script tag to our application and embed the images into the appropriate variables of type Class. The first iteration of our Script tag is below.

<mx:Script>
 <![CDATA[

 [Embed("assets/bioshock_small.png")]
 private var bioshock_icon:Class;
 
 [Embed("assets/crysis_small.png")]
 private var crysis_icon:Class;
 
 [Embed("assets/halo_small.png")]
 private var halo_icon:Class;
 
 [Embed("assets/neverwinternights_small.png")]
 private var neverwinter_icon:Class;
 
 [Embed("assets/wow_small.png")]
 private var wow_icon:Class;
 ]]>
</mx:Script>

The datagrid in the interface has the dataProvider property bound to the variable called cartContents which also needs to be added to our list of variables. We will later add the items dropped in our basket to the cartContents ArrayCollection.

[Bindable]
private var cartContents:ArrayCollection = new ArrayCollection();

Getting into the meat of the tutorial we are going to look at the functions that take care of creating and accepting the drag and drop actions. First we look at the function doDrag which starts the drag and drop action.

private function doDrag(event:MouseEvent):void
{
  var img:Image = event.currentTarget as Image;
  var dragImg:Image = new Image();
  dragImg.source = img.source;
 
  var dsource:DragSource = new DragSource();
  dsource.addData(img, 'img');
 
  DragManager.doDrag(img, dsource, event, dragImg);
}

Starting off I first get the image that is being clicked on. This is pulled simply by using the currentTarget of the event. We then create an image to use for the drag indicator and set the source to same thing as the image being dragged. Next I create a DragSource which is an object to hold data that needs to be passed with the drag event. I add a single piece of data which is a reference to the image being clicked and name the data "img" - which is the name I will later pull it out with. All that is left to do is actually start the drag event using the function doDrag on the DragManager class. I need to pass the object that is initializing the drag, the data source, the mouse event, and image for the drag indicator. That takes care of starting the drag.

We now want to allow the game to be dropped into the canvas that is labeled "basket". This is going to be done using the dragEnter event on the canvas. Which will fire when the item being dragged enters the canvas area. This function is simply going to add the canvas to the list of acceptable drop areas by adding itself using the function acceptDragDrop on the DropManager class.

private function dragAccept(event:DragEvent):void
{
  var dropTarget:Canvas = event.currentTarget as Canvas;
  DragManager.acceptDragDrop(dropTarget);
}

Once an item is dropped onto the canvas we probably want to do something. This is accomplished using the dragDrop event on the canvas. Once the drop happens we get the image from the data source that we passed along with the drag action and second we add the game to our shopping cart. This is done using the helper function addToCart which check to see if the game is in the cart and if so it increase the quantity and otherwise adds the game to the cart. I did however create a Game class (included in the source) to hold the name of the game and the number in the cart - done for data binding reasons. Both of the functions follow.

private function dragDrop(event:DragEvent):void
{
  var img:Image = event.dragSource.dataForFormat('img') as Image;
  addToCart(img);
}

private function addToCart(img:Image):void
{
  for(var i:int = 0; i < cartContents.length; i++)
  {
    if(cartContents[i].name == img.name)
    {
      cartContents[i].num++;
      return;
    }
  }
  cartContents.addItem(new Game(img.name, 1));
}

That takes care of drag and drop in Flex. Yes, it's that easy to do simple drag and drop and also very easy to expand to complex situations using the same techniques. I also need to give props to Belia0166 over at deviantArt for creating the icons that I used in the application. If anyone has any questions feel free to leave a comment. Also don't forget about the Drag and Drop Source Code.

Brad Simo
08/14/2008 - 11:48

Greetings:
I'm developing a Flex website and am trying to figure out the best way to integrate a shopping cart into it. I would rather not have to build one from scratch. On your blog, I looked at some of your examples that could be used as parts of a cart, but obviously I would have to add a bunch.

Do you have any info on what would be the best what to do develop a shopping cart for a flex site or is there company that sells a shopping cart that can integrate into a Flex site?

I would even be open to integrating with Yahoo, ebay or Amazon if there was a simple solution to do that. I'm just looking for a simple way to do this.

Any thoughts for suggestions would be GREATLY appreciated.

Thanks,
Brad

reply

Anonymous
10/21/2008 - 07:58

很棒,我也在学习FLEX,共同进步!

reply

Vidya
12/10/2008 - 00:21

Hi, i have two advanced datagrids.
and i want to do drag & drop between two datagrids. but the problem is with groupingCollection data.
wenever i try to drag item frm 1 datagrid to another it doesn’t get grouped into another datagrid.
i tried to refresh groupingCollection, dataprovider & also called valiadetNow() but it still remains non-grouped.
Could you please tell me wher problem lies?

reply

Anonymous
03/05/2009 - 20:50

共同进步

reply

Jimmy
03/11/2009 - 09:12

I am getting the error / warning

"Data binding will not be able to detect assignments to "bioshock_icon"

Can anybody tell me how to solve this

reply

The Fattest
03/11/2009 - 09:15

You can solve this by adding [Bindable] to that variable. However, you do not need it because we are only updating the class once with the Embed so we don't need to update when the icon changes.

reply

Mike
03/18/2009 - 23:10

How can I apply each item with a price so that I can display that also in the DataGrid?

reply

Mike
03/19/2009 - 00:52

Oops, I am ok. I forgot to work on Game.as Thanks.

reply

Asprilla
06/02/2009 - 09:26

This tutorial is great but I'm getting an error in the drapDrop function.

1119: Call to a possibly undefined property dragSource through a reference with static type flash.events:Event.

I'm using the code in an Air application, could that be the problem?

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.