HTML 5 code: drag and drop to a cart

With no framework, a demo with the source code to drap and drop HTML elements.

This demo offers to choose an object in a shop and move it to a cart... This allows you to see all the attributes and methods of the HTML 5 standard required to move items in a page.

Compatibility: IE 9, Chrome, Firefox.

The shop
My cart

The HTML 5 standard for drag and drop

The browser responds to each user action from the moment he clicks on an object and keeps the mouse button pressed, until he releases the mouse:

  1. Take an object on the page: click and hold down the button.
  2. Move the object on the page.
  3. Release the mouse button. If this is done in a dedicated area, the object is physically copied or moved in the page.

This assumes that you add event handlers to the two elements involved: the element to be moved and the area where it can be moved. The specification defines a list of events and attributes to be assigned to the elements of the page...

New HTML attributes

draggable
The property draggable = "true " indicates that HTML element can be moved on the page. It is useless for some elements that are movable by default, such as images. In the example of the cart we are moving images.
data-value
The value of this attribute is used to describe an object that can be moved. It will be used by event handlers if they must make a processing dependent of a given object.
dropzone
Attribute of a container in which you can place an object. The value of this attribute is "true" but varies based on the permissions granted. To accept a PNG image file, the value will be "file: image/png". For a text that will be "string:text". Other parameters may be included in the value. For example, the "move" value is added to allow movement.

The dataTransfer object

This is an interface for an object currently being moved in the page, that the JavaScript code can use. Its attributes:

DOMString dropEffect
We assign a type of operation to the move that the user initiated: " copy", "move ", "link " to add a link on the inital element or "none" to remove. This is assigned when the dragstart event is triggered .
DOMString effectAllowed.
Assigns the type of operation that the user is allowed when the object enters the target area, so when dragenter and dragover events are triggered. The assignment is made when the user get the object to move, so in the function associated with the dragstart event. To previous types of operations are also added "copyLink", "copyMove", "linkMove", "all " and "unitialized " (see the spec for uses).
DataTransferItemList items
This list is associated with any dataTransfe . Read-only, it can return a list of items to be moved. It has a length attribute, the attribute items, and methods clear(), add(DOMString data , type DOMString ), add(File data), and delete, a command to remove an item from the list to a given index.

And the interface has this methods :

setDragImage(Element image, x, y)
To assign an image to the moving object, replacing the image that is taken by the user.

Note: dataTransfer has other methods not in the specification and non-standard, they are not exposed here.

New events

The names in this list are used as such with addEventListener or preceded by "on" to be used as attributes of any HTML tags.

Two events are associated with each object that can be moved .

dragstart
To this event is assigned a function that contains the processing when the user initiates a move.
 
dragend
The event is associated with an object that can be moved to meet the end of movement. Contrary to drop, it is triggered even if the object is released out of the target area, so in our example, out of the cart.

And four events are related to the target.

dragenter
This event is triggered when an object enters the surface of the target container.
dragover
This event is added to the container tag to be activated when the mouse passes overs.
dragleave
Triggered when you release the object in move. If there are multiple targets in the page, it is triggered when leaving a target to enter another.
drop
This event is triggered when the user releases an object in the surface of the container tag, in the cart for our example.

Example of code in accordance with the standard

The shop in our example contains four objects :

<fieldset id="shop" class="shop">
  <legend>La boutique</legend>
  <img class="product" id="chair" src="image/chair.jpg" width="96" height="96">
  <img class="product" id="monitor" src="image/screen.jpg" width="96" height="96">
  <img class="product" id="bag" src="image/bag.jpg" width="96" height="96">
  <img class="product" id="transat" src="image/transat.jpg" width="96" height="96">
</fieldset>

You should know that since our objects are images, they are movable by default. If it were other elements we must add the draggable attribute either statically as below or dynamically as does the JavaScript code further:

<div class="product" draggable="true">
      <img src="images/chair.jpg" width="96" height="96">
</div> 

The cart of the user can be any type of container tag. As we use a fieldset containing a legend tag, we have added a layer for an empty container at the start:

<fieldset id="mycart" class="cart"><legend>My cart</legend>  
  <div id="cartArea"></div>
</fieldset>

Here is the complete JavaScript code, which we'll explain how it works then:

<script>
var cartArea = document.querySelector('#cartArea'); 

var prods = document.querySelectorAll('.product');
for(var i = 0; i < prods.length; i++)
{
  prods[i].setAttribute('draggable', 'true');  // optionnel avec des images
  prods[i].addEventListener('dragstart', function(evnt) {
  this.className = 'itemchoosen';
  evnt.dataTransfer.effectAllowed = 'copy';
  evnt.dataTransfer.setData('text', this.id);
  return false;
  }, false);
}

cartArea.addEventListener('dragover', function(evnt) {
   if (evnt.preventDefault) evnt.preventDefault();
   evnt.dataTransfer.dropEffect = 'copy';
   return false;
}, false);
   
cartArea.addEventListener('dragenter', function(evnt) {
    return false;
}, false);

cartArea.addEventListener('dragleave', function(evnt) {
   return false;
}, false);

cartArea.addEventListener('drop', function(evnt) {
  if (evnt.stopPropagation) evnt.stopPropagation();

  var id = evnt.dataTransfer.getData('text');
  var theitem = document.getElementById(id); 
  // theitem.parentNode.removeChild(theitem);   // une option non retenue ici
  theitem.className='itemblurred';
  var y  = document.createElement('img');
  y.src = theitem.src;
  cartArea.appendChild(y);
  evnt.preventDefault(); // pour Firefox
  return false;
}, false);
</script>

The code in details

The list of HTML objects figuring the products is obtained with the querySelectorAll method. It is a choice among other. Then added to each tag representing a product the draggable property for demonstration purposes (it works without , as we move images) . Then each tag has a dragstart event and a function that responds to this event is associated .
In our example, when initiating a move in the page, the product image get a red border.
The content to be transferred is defined by dataTransfer.setData. We gives it the text format and the id of the tag representing a product.

var prods = document.querySelectorAll('.product');
for(var i = 0; i < prods.length; i++)
{
  prods[i].setAttribute('draggable', 'true');  // optionnel avec des images
  prods[i].addEventListener('dragstart', function(evnt) {
  this.className = 'itemchoosen';
  evnt.dataTransfer.effectAllowed = 'copy';
  evnt.dataTransfer.setData('text', this.id);
  return false;
  }, false);
}

We associate the dragEnter and dragLeave events to the tag in which we want to place the objects. In our example, no processing is added.

Also is associated dragOver. This is an opportunity to assign an effect.

cartArea.addEventListener('dragover', function(evnt) {
   if (evnt.preventDefault) evnt.preventDefault();
   evnt.dataTransfer.dropEffect = 'copy';
   return false;
}, false); 

And finally we add the drop event which assigns a processing to execute when the object is put in the cart.

cartArea.addEventListener('drop', function(evnt) {
  if (evnt.stopPropagation) evnt.stopPropagation();
  var id = evnt.dataTransfer.getData('text');
  var theitem = document.getElementById(id); 
  // theitem.parentNode.removeChild(theitem);
  theitem.className='itemblurred';
  var y  = document.createElement('img');
  y.src = theitem.src;
  cartArea.appendChild(y);
  evnt.preventDefault(); // for Firefox
  return false;
}, false);

This is the most complex function (in our example) and the most important and therefore it deserves to be explained in detail.

  1. Calling stopPropagation prevents triggering events that could result from that we change the page.
  2. The contents of dataTransfer is retrieved, in this case the id of the product.
  3. This allows to place the corresponding variable in the theitem HTML element.
  4. We can at this point remove the object in the store with the removeChild DOM method. That is ok for some program where the goal is to move objects on the page, but not in our example, so I added this statement to memory in comment.
  5. To insert the picture in the cart, we create an image tag and assign to the source attribute that of the moved object, and we add this tag as a child of the cartArea container.
  6. To cancels the execution of events by default we call preventDefault. This is needed in Firefox.

This program is just a demonstration. You can take the code structure and associate different processings to the events, depending on the application to build. In the case of an online store, the objects added to the cart are not removed from the original list because you can several. In other cases, the move is material, we remove the object at a point to place it in another .

The CSS code is specific to this example and is a choice. You can see the source in the demo page.

This demo page provides easier access to the JavaScript and CSS source code. Its use is totally free (except as a tutorial on the web).

References