http://www.developer.com/lang/using-html5-drag-and-drop-in-asp.net.html

Back to article

Using HTML5 Drag and Drop in ASP.NET


March 5, 2012

Introduction

Drag and drop operations are common in desktop applications. Modern web applications also try to harness the ease and power of drag and drop operations to provide enhanced user experience. Web developers often resorted to JavaScript based libraries or custom techniques for enabling drag and drop behavior in their applications. Luckily, HTML5 comes with an inbuilt support for drag and drop. Using drag and drop features, you can drag an HTML element and drop it onto another. In the process you can also pass data from the source element to the target element. Integrating drag and drop with server side processing allows you to provide rich user experience. This article illustrates how HTML5 drag and drop features can be used in an ASP.NET website.

Enable Dragging for HTML Elements

The first step in using the drag and drop features of HTML5 is to make one or more elements draggable. You do this by setting the draggable attribute of an HTML element to true. For example, the following piece of markup makes a <DIV> element draggable:

<div class="myclass" draggable="true">Some content</div>

Drag and Drop Events

Marking one or more DOM elements as draggable is just a part of the story. To actually make your drag and drop functional and visually appealing to the end user you need to handle certain events. These events are listed below :

 

Event

Description

dragstart

This event is raised when the drag operation begins.

drag

This event is raised when an element is dragged.

dragenter

This event is raised when a draggable element is dragged and enters a valid drop target.

dragleave

This event is raised when a draggable element that was dragged on a valid drop target leaves the drop target.

dragover

This event is raised when a draggable element is being dragged over a valid drop target.

drop

This event is raised when a dragged element is dropped onto a valid drop target.

dragend

This event is raised when the drag operation ends.

You can wire event handlers to these events in two ways viz. in the DOM element markup using onxxxx syntax or using JavaScript (or a JavaScript based library such as jQuery). The following markup and code shows both the ways.

<div class="myclass" draggable="true" ondragstart="OnDragStart" ondrop="OnDrop"></div>
$("div").each(function () {
  this.addEventListener('dragstart', OnDragStart, false);
  this.addEventListener('drop', OnDrop, false);
});

Notice how the above code uses addEventListener() method in jQuery code to attach event handlers.

Transferring Data Between Drag and Drop Operations

Most of the times dragging something and dropping it onto something else also calls for transferring some data between the source and the target elements. To accomplish this data transfer HTML5 provides DataTransfer object. The following table lists some of the important properties and methods of DataTransfer object.

Property / Method

Description

effectAllowed

Indicates the types of operations that are to be allowed. The possible values are none, copy, copyLink, copyMove, link, linkMove, move, all and uninitialized.

dropEffect

Indicates the type of operation that is currently selected. If the type of operation is not supported by the effectAllowed attribute, then the operation will fail. The possible values are none, copy, link, and move.

setDragImage()

Sets the given element that is shown during drag operation.

setData()

Sets a specific data that is to be transferred.

getData()

Retrieves previously set data for further processing.

clearData()

Removes the previously stored data.

You will typically use the properties and methods of dataTransfer object in the dragstart and drop event handlers.

Performing Drag and Drop

Now let's put the knowledge you learned so far in a simple yet functional application. Begin by creating a new ASP.NET Website. You will create a simple web form that resembles the following figure :

A simple web form
A simple web form

NOTE: The example is tested on the latest version of FireFox but it should run on latest versions of other major browsers too.

As you can see the web form represents a simple shopping cart. Various products are represented by DIV elements placed inside a DataList control. The products can be dragged and dropped onto the shopping bag. Once all the required products are added, you can click on the "Place Order" button to send product data to the server to place an order.

The above example makes use of the Entity Framework data model as shown below. You can get the SQL Server Express database and the model from the code download accompanying this article.

The example makes use of the Entity Framework data model
The example makes use of the Entity Framework data model

The data model shown above includes only basic details. In a more real world shopping cart system you will capture many more details.

The product catalog is a DataList control whose ItemTemplate contains a draggable <DIV> element. This DIV wraps all the product details for an individual product.

<asp:DataList ID="DataList1" runat="server" DataSourceID="EntityDataSource1" RepeatDirection="Horizontal">
    <ItemTemplate>
        <div class="product" draggable="true">
            <header><%# Eval("Name") %></header>
            <div><asp:Image runat="server" ID="img1" ImageUrl='<%# Eval("ImageUrl") %>' /></div>
            <div><%# Eval("Description") %></div>
            <br />
            <div><%# Eval("Cost","Cost : ${0}") %></div>
        </div>
    </ItemTemplate>
</asp:DataList>
<div class="bag">
    <asp:Image runat="server" ID="img1" ImageUrl="~/images/cart.jpg" />
    <br /><br />
    <input id="Button1" type="button" value="Place Order" />
    <br />
    <input id="Button2" type="button" value="Clear Cart" />
</div>

Notice how the DIV elements representing products are marked with the draggable attribute set to true. The product CSS class that takes care of the look and feel of the products is shown below:

.product
{
    height: 300px;
    width: 150px;
    float: left;
    border: 2px solid #666666;
    background-color: white;
    padding:3px;
    margin:5px;
    text-align: center;
    cursor: move;
}

The shopping cart is also a DIV element with CSS class bag.

.bag
{
    padding:10px;
    text-align: center;
    cursor: move;
}

The next step is to wire drag and drop event handlers to various elements. You will use jQuery to do that, so make sure to refer jQuery library in the <head> section.

<script src="scripts/jquery-1.4.4.min.js"
type="text/javascript"></script>

The jQuery code that wires various event handlers should be written in the ready() event handler and is shown below:

$(document).ready(function () {
    $("div .product").each(function () {
        this.addEventListener('dragstart', OnDragStart, false);
    });
 
    $("div .bag").each(function () {
        this.addEventListener('dragenter', OnDragEnter, false);
        this.addEventListener('dragleave', OnDragLeave, false);
        this.addEventListener('dragover', OnDragOver, false);
        this.addEventListener('drop', OnDrop, false);
        this.addEventListener('dragend', OnDragEnd, false);
    });
})

As you can see, the first each() call adds an event listener for dragstart event. All the product DIV elements should handle this event so the code filters the elements based on the  CSS class product. Similarly, the shopping cart element should handle other events, especially drop.

The following markup shows the complete event handler functions OnDragStart, OnDragEnter, OnDragLeave, OnDragOver, OnDrop and OnDragEnd.

function OnDragStart(e) {
    this.style.opacity = '0.3';
    srcElement = this;
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text/html', $(this).find("header")[0].innerHTML);
}
 
function OnDragOver(e) {
    if (e.preventDefault) {
        e.preventDefault();
    }
    $(this).addClass('highlight');
    e.dataTransfer.dropEffect = 'move';
    return false;
}
 
function OnDragEnter(e) {
    $(this).addClass('highlight');
}
 
function OnDragLeave(e) {
    $(this).removeClass('highlight');
}
 
function OnDrop(e) {
    if (e.stopPropagation) {
        e.stopPropagation();
    }
    srcElement.style.opacity = '1';
    $(this).removeClass('highlight');
    var count = $(this).find("div[data-product-name='" + e.dataTransfer.getData('text/html') + "']").length;
    if (count <= 0) {
        $(this).append("<div class='selectedproduct' data-product-name='" + e.dataTransfer.getData('text/html') + "'>" + e.dataTransfer.getData('text/html') + "</div>");
    }
    else {
        alert("This product is already added to your cart!");
    }
    return false;
}
 
function OnDragEnd(e) {
    $("div .bag").removeClass('highlight');
    this.style.opacity = '1';
}    

Let's examine each of the event handlers shown above.

OnDragStart

function OnDragStart(e) {
    this.style.opacity = '0.3';
    srcElement = this;
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text/html', $(this).find("header")[0].innerHTML);
}

The dragstart event handler reduces the opacity of the element being dragged so that the end user gets a visual clue about the drag operation. The source of drag operation is stored in a global variable srcElement because we need it later in the drop event handler. The effectAllowed property of dataTransfer object is set to move. Additionally the setData() method sets the data to be transferred to the innerHTML of the header element (i.e. product name) in the dataTransfer object. This way drop event handler knows which product is to be added to the shopping cart. The first parameter of setData() method indicates the type of data that is being transferred ('text/html' in this case).

OnDragOver

function OnDragOver(e) {
    ...
    $(this).addClass('highlight');
    e.dataTransfer.dropEffect = 'move';
    return false;
}

The dragover event handler adds a CSS class to the drop target so as to give a visual clue to the end user about the operation. The highight CSS class is shown below:

.highlight
{
    background-color:Yellow;
}

The OnDragOver function also sets the dropEffect of the dataTransfer object to move.

OnDragEnter and OnDragLeave

function OnDragEnter(e) {
    $(this).addClass('highlight');
}
 
function OnDragLeave(e) {
    $(this).removeClass('highlight');
}

The dragenter and dragleave event handlers are simple and merely add and remove the highlight CSS class to the target element.

OnDrop

function OnDrop(e) {
    ...
    srcElement.style.opacity = '1';
    $(this).removeClass('highlight');
    var count = $(this).find("div[data-product-name='" + 
                e.dataTransfer.getData('text/html') + "']").length;
    if (count <= 0) {
        $(this).append("<div class='selectedproduct' data-product-name='" + 
        e.dataTransfer.getData('text/html') + "'>" + 
        e.dataTransfer.getData('text/html') + "</div>");
    }
    else {
        alert("This product is already added to your cart!");
    }
    return false;
}

The drop event handler sets the opacity of the source element back to 1 since drag and drop operation is complete. It also removes the highlight CSS class from the target element. It then appends the product being dragged to the target element. Notice the use of the getData() method to retrieve the data previously set in the dragstart event handler. There is also a check so that the same product cannot be added multiple times.

OnDragEnd

function OnDragEnd(e) {
    $("div .bag").removeClass('highlight');
    this.style.opacity = '1';
}

The dragend event handler simply removes the highlight CSS class from the drop target.

Passing Data from Client to Server

To actually transfer shopping cart items to server side code, you need to make use of $.ajax() method of jQuery. The click event handler of "Place Order" has the relevant code and is shown below:

$("#Button1").click(function () {
    var data = new Array();
    $("div .bag div").each(function (index) {
        data[index] = "'" + this.innerHTML + "'";
    });
    $.ajax({
        type: 'POST',
        url: 'shoppingcart.aspx/PlaceOrder',
        contentType: "application/json; charset=utf-8",
        data: '{ products:[' + data.join() + ']}',
        dataType: 'json',
        success: function (results) { alert(results.d); },
        error: function () { alert('error'); }
    });
});

As you can see, the $.ajax() calls a web method PlaceOrder residing inside the ShoppingCart.aspx web form. The PlaceOrder web method is shown next.

[WebMethod]
public static string PlaceOrder(string[] products)
{
    Guid orderId = Guid.NewGuid();
    DatabaseEntities db = new DatabaseEntities();
    foreach (string p in products)
    {
        Order order = new Order();
        order.OrderId = orderId;
        order.ProductName = p;
        order.Qty = 1;
        db.Orders.AddObject(order);
    }
    db.SaveChanges();
    return "Order with " + products.Length.ToString() + " products has been added!";
}

The PlaceOrder web method simply puts an order details in the Orders table. The PlaceOrder() web method accepts an array of strings that represents product names. Notice how $.ajax() passes the products parameter in JSON format. Upon successful completion of the web method, the success handler function simply displays an alert to the end user.

Now run the web form, drag and drop one or more products onto the shopping cart and then click on the "Place Order" button to pass the product names from the shopping cart to the server.

Summary

HTML5 provides a native way to enable drag and drop in your web pages. Using these features you can enhance the end user experience making your website more interactive and easy to use. The draggable attribute of DOM elements govern whether an element can be dragged or not. The events dragstart, dragenter, dragleave, dragover, drop and dragend allow you to take control of the overall drag and drop operation. The dataTransfer object allows you to transfer data between drag source and drop target. The setData() and getData() methods of dataTransfer object do the job of setting the data to be transferred and retrieving the data that was transferred respectively.

Download the code for this article.

Sitemap | Contact Us