3.3 Drag and drop

In notebook:
edX Advanced HTML5
Created at:
2016-01-18
Updated:
2016-11-15
Tags:

Add ​ondragstart​ event handler to the containing html element and add ​draggable="true"​ attribute to its children html elements.

<ol ondragstart="dragStartHandler(event)">
   <li draggable="true" data-value="fruit-apple">Apples</li>
   <li draggable="true" data-value="fruit-orange">Oranges</li>
   <li draggable="true" data-value="fruit-pear">Pears</li>
</ol>

It's the draggable children that will fire the events (similar to click bubbling/delegation).

Detecting drop and using the dragged elements

Michel uses the ​data-value​ attribute of the draggable elements and copies it to the "drag and drop clipboard" to use it later. This is the ​event.dataTransfer.setData(target_type, value)​ :
  function dragStartHandler(event) {
    console.log('dragstart event, target: ' + event.target.innerHTML);
    // Copy to the drag'n'drop clipboard the value of the
    // data* attribute of the target,
    // with a type "Fruit".
    event.dataTransfer.setData("Fruit", event.target.dataset.value);
 }

The "drop zone"

It's an HTML element with an ​ondrop​ event handler

<div ondragover="return false" ondrop="dropHandler(event);">
Drop your favorite fruits below:
 <ol id="droppedFruits"></ol>
</div>

The ondragover="return false" will avoid propagating dragover events that may occur in high number

The drop handler will use the content from "clipboard"

using the event.dataTransfer.getData(target_type) method;

function dropHandler(event) {
   console.log('drop event, target: ' + event.target.innerHTML);
   ...
   // get the data from the drag'n'drop clipboard,
   // with a type="Fruit"
   var data = event.dataTransfer.getData("Fruit");
   // do something with the data
   ...
}

Adding visual feedback

​dragstart​ and ​dragend​ can be used to toggle CSS classes on the html elements
More events to observe on the drop zone:
  • ​dragenter​ entering the drop zone
  • ​dragleave leaving the drop zone (moves out, set back style to original)
  • ​dragover​ best practice is to prevent propagation of the event and also prevent the default behaviour of the browser (i.e. open image on a new tab)
  • ​drop​ where we can process the drop (get the value from the clipoard). also resetting the styling of the drop zone

Visual feedback on the cursor

To give this visual feedback, we use the effectAllowed and dropEffect properties of the dataTransfer object. To set one of the possible predefined cursors, we allow an effect in the dragstart handler, and we set the effect (to "move", "copy", etc.) in the dragEnter or dragOver handler.

function dragStartHandler(event) {
    // Allow a "copy" cursor effect
    event.dataTransfer.effectAllowed = 'copy';
    ...
}

And here is where we can set the cursor to a permitted value:

function dragEnterHandler(event) {
   // change the cursor shape to a "+"
   event.dataTransfer.dropEffect = 'copy';
   ...
}

To set a custom image, we also do the following in the dragstart handler:

function dragStartHandler(event) {
   // allowed cursor effects
   event.dataTransfer.effectAllowed = 'copy';
   // Load and create an image
   var dragIcon = document.createElement('img');
   dragIcon.src = 'anImage.png';
   dragIcon.width = 100;
   // set the cursor to this image, with an offset in X, Y
   event.dataTransfer.setDragImage(dragIcon, -10, -10);
   ...
}

#####All possible values for dropEffect and effectAllowed:

dataTransfer.effectAllowed can be set to the following values: none, copy, copyLink, copyMove, link,linkMove, move, all, and uninitialized.

dataTransfer.dropEffect can take on one of the following values: none, copy, link, move.

Drag and drop images or any HTML element

​<img>​ elements are draggable by default (no need for ​draggable=true​ attribute)
  1. each img has an id
  2. copy this id to the drag'n'drop clipboard (​evt.dataTransfer.setData("Text", target.id))
  3. on drop, get the id, get the img with this id and insert into the html tree: (var id = evt.dataTransfer.getData("Text");  target.appendChild(document.getElementById(id));​)

Drag and drop a text selection

There is no need to add a dragstart handler on an element that contains text. Any selected text is automatically added to the clipboard with a name/key equal to "text/plain". Just add a drop event handler on the drop zone and get the data from the clipboard using "text/plain" as the access key:

function drop(target, event) {
   event.preventDefault();
   target.innerHTML = event.dataTransfer.getData('text/plain');
};