Learning Flex – Lesson 12, Using Drag and Drop

All Flex components support drag and drop and a subset have additional functionality which greatly simplifies implementation. List based components have this capability which introduces two main properties: dragEnabled, a boolean value (defaulted to false) which specifies if the control can act as a drag initiator and dropEnabled, a boolean value (defaulted to false) which specifies if the control can act as a drop target.

Flex will decide what to drop based on things such as liked named properties between the source and destination. If it can’t figure anything from this, the whole object will be dumped and you’ll see something like [object Object]. To avoid this and work with components that do not have the enhanced capability, there are various events we can use.

Drag Initiator Events

mouseDown, mouseMove (MouseEvents class) – although not specific to drag/drop operations, these mouse events are used for components that do not have a dragEnabled property. The mouseDown event is fired when the user selects a control and holds down the mouse button. The mouseMove event is fired when the mouse moves.

dragComplete (DragEvent class) – this event fires when a drag operation is finished as the user releases the mouse button, either when the data drops on a target or the drag is abandoned.

Drag Target Events

All these events are part of the DragEvent class.

dragEnter – fires when a drag proxy (the image displayed during the drag) moves into the target component.

dragOver – fires when the user moves the pointer over the target.

dragDrop – fires when the mouse is released over the target.

dragExit – fires when the user drags outside the target but does not drop the object.

There are several operations that need to take place for drag/drop to be implemented;

At the source:

  • recognize the user may be about to drag (mouseDown event)
  • assign relevant data to a DragSource object

At the destination:

  • recognize something is being dragged into the component (dragEnter event)
  • make sure this is an object that can be accepted by this component
  • recognize if the object is dropped (dragDrop event)
  • process the dropped object

For the source component, there are two classes that must be included: mx.core.DragSource, mx.managers.DragManager. Next, specify an event handler for the mouseDown event on the component. It will require the following parameters – the component, the data to be passed, the event and a format String. The format is used by potential destinations to determine if the object being dragged in is valid for dropping on them.

In the mouseDown event handler, define a new DragSource object and use it’s addData() method to add the data object to be passed and the format string for that data. Note that you could store multiple data types with different formats in this DragObject so that different destinations could represent the object in different ways (maybe text in one and an image in another for example). Finally, call the static method DragManager.doDrag() specifying the object you’re dragging from, the DragSource object you’ve just created and the mouseDown event.

For the destination, start by defining an event handler for the dragEnter event, passing the event and the acceptable format string for this component. In the handler, the first thing to do is check that the dragged object contains a valid format. This is achieved by calling event.dragSource.hasFormat(formatName). The method returns true if the format is found. If the format’s ok, call the static method DragManager.acceptDragDrop(IUIComponent(event.target)) using the event.target rather than the destination container keeps the method more generic and re-usable.  This will remove the red ‘X’ on the dragged visual indicator when it enters the component.

The next stage is to define an event handler for the dragDrop event. Pass in the event and the acceptable format. In the event handler, start by defining a temporary Object variable to hold the dropped data. The data can be retrieved by calling event.dragSource.dataForFormat(formatName) . We need to provide the format name as there could be multiple supported formats. Finally use the addItem() method on the container’s dataProvider to show the data at the destination.

If you are overriding the default behavior of  a drag/drop enhanced container (to prevent [object Object] showing up for example) you only need to define the dragDrop event handler. Note that the format name associated with data in a DataGrid is “items“. One additional task is to add event.preventDefault() to the end of your handler so the default drop behavior is not executed.

One of the other drag/drop behaviors you can change is the drag proxy. A common choice is to make this an image representing the data. By default, the drag/drop operation removes the drag proxy from the source so if you have the image in your source container and provide it’s id as the proxy, it will be removed. To prevent this, declare a new version of the image. Withing the mouseDown event handler, define a new Image object and use it’s load() method to load it from the file system. By default, the width and height of a new image are set to zero so you should provide values for these properties to be able to see it (80×80 is a good starting point). Then in the doDrag method call, add the image object as the fourth parameter.