A frequently overlooked and underused feature of Dojo’s Drag-and-Drop (DnD) module is drag handles.

DnD is commonly implemented as a set of draggable elements where the entire DnD item (usually a subtree of DOM nodes) can detect the drag action. In some cases, this is not desirable:

  • DnD items that contain active elements: links, text areas, buttons, check boxes, other common form elements. The drag action can prevent normal interactions with them, e.g., text selection inside text boxes.
  • Large DnD items that occupy most of screen. Frequently these items have collapsed and expanded states, and should not be dragged while expanded.

So how do we deal with these cases? There is a simple user interface solution: provide well-marked drag handles. If you look at your favorite graphical user interface, you can see that this metaphor is used for dragging windows: if you want to move a window on your screen, you drag it grabbing a window title. This convention allows us to interact with the content of the window as we please, yet we have our freedom to rearrange windows as we want.

Simple List with Drag Handles

Let’s implement a simple list with drag handles using Dojo markup for simplicity:

Source with handles. Items should be draggable by "Item".

Item Alpha

Source without handles.

Item Epsilon

As you can see, we define a bunch of items marked with dojoDndItem class, and inside they all contain an element marked with the dojoDndHandle class. The first source allows users to drag our items using handles only (withHandles="true"). The second source is a plain vanilla container that only uses defaults. It will ignore our special markup and will drag items regardless of how we started to drag them. This behavior is dynamic — placing items from the second container to the first container makes them to switch behavior automatically (no handles/use handles).

Of course we want to include Dojo — I’ve decided to use Google CDN in my examples so I don’t need to deploy Dojo locally, and to take advantage of Google’s geographically distributed fast network for my humble web application. Additionally, we specify parsing on load (so markup can be processed automatically), and ask for the dojo.dnd.Source module to be included:



You can see that this example has no JavaScript code besides requesting a module!

Check out the simple list with drag handles example.

the container of the 1st example

Note that active handles have a light pink background. Go to the live code and try dragging items between containers and see how their behavior changes automatically. Don’t forget to inspect the source code of that page to see all details!

Playing with this and other examples, you will see that by trying to drag an item outside of its handle, it will select text and nodes. This is the expected behavior. I didn’t suppress it to show you that this feature continues to work. To suppress this behavior, just add this one line of code:

dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent);

Or you can do it on per-container basis.

What we just did is included in the Dojo DnD test suite. It explains different selection and drop modes available for Dojo DnD containers. By default, for example, you can select multiple items and move/copy them at once. This is very handy functionality for power users of your web applications.

Does it mean that a DnD item is allowed to have just one handle? No. You can implement any number of handles per item, and be as flexible as you like.

Multiple Drag Handles

Let’s implement a different example with multiple drag handles. We’ll replace the first container:

Head Alpha Tail

As you can see it looks the same, with the addition of two handles (“head” and “tail”).

Check out the multiple drag handles example.

the container of the 2nd example

You can see that each item has two drag handles. Try dragging items using both handles between containers and see how they behave. Or try to move items from the second container to the first container — now it contains items with a different number of handles!

An unrestricted number of drag handles provides for more flexibility while designing user interfaces. It begs the question: is it possible to have 0 (zero) drag handles per DnD item? Yes. Is it possible to add and remove drag handles dynamically? Yes.

Dynamic Drag Handles

Let’s implement dynamic drag handles that can be added or removed on the fly. Let’s update the first container again:

Item Alpha

Changes from the first example are minimal — I have included a checkbox to add/remove the dojoDndHandle class dynamically. And yes! The source code for this is simply:

change = function(checkbox){
  var item = checkbox.parentNode.parentNode,
      handle = dojo.query("span", item);
  handle[checkbox.checked ? "addClass" : "removeClass"]("dojoDndHandle");
};

The code is super simple: it takes a checkbox element, calculates a DnD item node (two parents up), gets all <span> elements and adds or removes the dojoDndHandle class conditionally. This function is called from the onchange event handler attached to every checkbox. As you can see we don’t need to register the change with containers or any other DnD objects.

Check out the dynamic drag handles example.

the container in the 3rd example

As you can see, all items now have a checkbox, and I have already turned it off on the 3rd item. Now go to the live code and try moving items between both containers, changing their state dynamically. Experimenting with this example you can observe several interesting things:

  • If you move items with a checkbox to the second container, you can still click the checkbox but it behaves oddly if the mouse moves a small amount during the click.
  • “Deactivated” items in the first container cannot be moved, but you can still use these items to guide drop points around them.
  • Another useful property of “deactivated” items: their relative order is immutable. If item “B” follows item “A” in the container, it will continue to do so regardless of how we manipulate all other items. The most we can do is to add or remove more items between them.
  • Items in the second container can be moved regardless of their status.

Conclusion

Dojo DnD module (dojo.dnd) is a powerful tool for building rich interactive user interfaces with a small code base. Leveraging available CDN solutions and relying on Dojo markup you can quickly build web pages with capabilities unthinkable just two to three years ago.

Stay tuned for more inside Dojo articles!