Sunday 17 April 2011

HTML 5 - Drag and Drop


So, every developer loves looking into new things right? Well I'm no different so with HTML 5 predicted to be the hot new technology on the block, I thought it only right that I take a bit of time to look into it. So, every now and again I'll be posting information regarding what new options HTML 5 will give us and today, I'm going to start with the drag and drop specification.

At the time of writing this, I have three browsers installed on my computer, Internet Explorer 9, Firefox 4 and Google Chrome 11. Drag and drop is only currently supported by two of these, Firefox and Chrome, so if you're not using one of those, none of the demo's provided in this post will work.

So, the HTML 5 specification provides us with a seven new JavaScript events to listen for:
  • dragstart
  • drag
  • dragenter
  • dragleave
  • dragover
  • drop
  • dragend
There's also a new property for HTML elements called draggable, just by setting it to true will enable an element to be draggable, for example:



Try dragging me, you should be able to move me around, although you can't drop me anywhere.

So, now we've made an element draggable, we need to be able to drop it somewhere. Using the events above, we can do just that. But first, let me quickly describe what each event is used for.

dragstart
As with most of these events, it does exactly what it says on the tin. This event fires when you very first try attempting to drag the element to which the event is attached. Returning true will enable the drag, returning false won't.

drag
Fires while you're dragging something. Essentially the same as onmousemove but obviously, only fires while you're dragging something.

dragenter
Fires when you first drag an element over the target element to which this event is attached. Return false if the target element is a drop zone.

dragleave
Fires when your mouse leaves the elements to which this event is attached while dragging another element.

dragover
Fires as you drag an element over the target element to which this event is attached. A little oddly, you need to return false if the target element is a drop zone.

drop
Fires when the user releases the mouse button while dragging over the target element that has this event attached, effectively dropping the dragged element.

dragend
Essentially the same as the drop event as in it fires when the user has released the mouse button while dragging the element, except this event is usually placed on the element being dragged rather than the drop zone element.

Now we know what all the events are used for, we can put together a clever combination and come up with a simple demo.

I'm draggable between the two grey boxes.

So, lets look at the HTML for this...

<table border="0" cellpadding="10" cellspacing="10" style="width: 100%;">
  <tbody>
     <tr>
       <td style="text-align: center;" width="50%">
          <div id="zoneOne" ondragenter="return dragEnter(event);" ondragover="return dragOver(event);" ondrop="return dragDrop(event);" style="background-color: grey; height: 100px; padding: 5px; text-align: center; width: 100%;">
              <div id="dragObj" draggable="true" ondragend="return dragEnd(event);" ondragstart="return dragStart(event);" style="background-color: red; margin: 5px; padding: 10px; width: 50%;">
I'm draggable between the two grey boxes.
              </div>
          </div>
       </td>      
       <td width="50%">
           <div id="zoneTwo" ondragenter="return dragEnter(event);" ondragover="return dragOver(event);" ondrop="return dragDrop(event);" style="background-color: grey; height: 100px; padding: 5px; text-align: center; width: 100%;">
           </div>
       </td>   
    </tr>
  </tbody>
</table>

I've highlighted the drag and drop related mark up in red. There's nothing special here, we mark our draggable element by setting the draggable property to true on that element. Then the rest is just event mapping. We map the dragstart and dragend events to the element that we're going to be dragging around screen. We then map the dragenter, dragover and drop events on the drop area elements. So, what do those mappings do?

Here's the code for them:

  function dragEnter(ev){
    return false;
  }
  function dragDrop(ev){
    var idelt = ev.dataTransfer.getData("Text");
    var elem = document.getElementById(idelt);
    ev.target.appendChild(elem);
    ev.stopPropagation();
    return false;
  }
  function dragOver(ev){
    return false;
  }
  function dragStart(ev){
    ev.dataTransfer.effectAllowed='move';
    var id = ev.target.getAttribute('id');
    ev.dataTransfer.setData("Text", id);
    return true;
  }
  function dragEnd(ev){
    ev.dataTransfer.clearData("Text");
    return true;
  }

Now, a quick walkthrough of each function...

  • dragEnter always returns false. There's no conditions on which I don't want the draggable item to be droppable within the area defined.
  • dragOver function does the same as the dragEnter for the same reason.
  • dragStart function sets the effectAllowed property of the dataTransfer object. This defines what the drag and drop event is actually allowed to do, in this case we say we can move it. Then we set the type of data that we want to move, in this case it's just text which we'll make the ID of the element we're dragging around. 
  • drop function then grabs that id defined within dragStart, finds the element with that id and then append its to our drop zone, effectively moving it from one zone to another.
  • dragEnd function just clears out the ID we were storing so it doesn't interfere with any future drag and drop operations.

As you've seen, I've made use of the dataTransfer object. This object only exists within the event object when we're dealing with a drag and drop operation. It essentially stores information regarding the operation as it happens. So, you can set the effectAllowed property which defines what effects are allowed within this drag and drop operation. The getData and setData methods allow us to store information regarding the operation, essentially saving us having to define extra global variables that all the functions need access to. For more information on the dataTransfer object and it's members, take a look here.

Ok, well, that's it for drag and drop. I think the next HTML 5 demo I'll be looking at, which is kind of related, is the HTML 5 File API, which will effectively allow users to be able to drag files from their desktop straight on to your web application and in the process, will upload the file to your web server. I believe this is now supported by Gmail to upload file attachments and it's all very clever stuff. More on that at a later date!

No comments:

Post a Comment