Drag and Drop Actions

For a DnD application to be really useful, you would require mechanism to add user defined actions for different DnD events. This could be anything from updating a text box value to sending data back to server using AJAX. In this chapter we will see how to hook up actions to DnD events. This can be achieved with the publish/subscribe mechanism.

The following messages can be subscribed to :

  • /dnd/source/over
  • /dnd/start
  • /dnd/drop
  • /dnd/cancel
Given below is code snippet that attaches a callback function to a message:
dojo.subscribe("/dnd/drop", function(source,nodes,iscopy){
  //code to perform some action			
});

dojo.subscribe("/dnd/start", function(source,nodes,iscopy){
  //code to perform some action		
});

dojo.subscribe("/dnd/source/over", function(source){
  //code to perform some action	
});

dojo.subscribe("/dnd/cancel", function(){
  //code to perform some action	
});
The parameters to the callback function are:
  • source : Source of the nodes which are being dragged/dropped.
  • nodes: Array of HTML node objects. To get corresponding DnDItem object use the following method:
    var jsnode = source.getItem(nodes[0].id);
    var d = jsnode.data;
    var t  = jsnode.type;
  • iscopy: This parameter is a boolean , which is true for a copy operation and false for drag operation.

If you are interested in getting the target object, then you can use following method:

var t = dojo.dnd.manager().target;
When we create a target or source via markup, we can specify a name for global level javascript variable for it, using the jsId attribute.
<div dojoType="dojo.dnd.Source" jsId="cart" class="target" accept="red,blue" id="target1">
</div>
This automatically creates a global variable 'cart' of the type "dojo.dnd.Source".

DnD Events Example
Now let us have a look at simple example of DnD events. In this example, I have created a simple shopping cart. Each blue and red sphere inside the source(shelf) has some price associated with it. This is assigned using the 'dndData' item. You can select multiple spheres from the source(shelf) and drop them onto the target (shopping cart). You will see the updated total price of your cart items. If you drop certain items back to the shelf, the corresponding amount is deducted from the total. I have attached a text file with this article which contains complete source. You will require BLUE.png and RED.png images to run the example.

Below is a excerpt from the file followed by explanation :

<script type="text/javascript"> 
dojo.require("dojo.dnd.source"); // capital-S Source in Dojo 1.0

var item_price;
var total = 0;
function AddItems(target,nodes)
{
	for (var i=0;i<nodes.length;i++)
	total += parseFloat((target.getItem(nodes[i].id)).data);
	dojo.byId("cost").innerHTML = total;
}

function SubstractItems(target,nodes)
{
	for (var i=0;i<nodes.length;i++)
	total -= parseInt((target.getItem(nodes[i].id)).data);
	dojo.byId("cost").innerHTML = total;
}
	
function ShowPrice(target,nodes)
{	var sum =0;
	for (var i=0;i<nodes.length;i++)
	sum += parseInt((target.getItem(nodes[i].id)).data);
	dojo.byId("msg").innerHTML = "Selected Item Price is $"+ sum ;
}

function ClearMsg()
{   dojo.byId("msg").innerHTML = "";}

function init()
{
	
	dojo.subscribe("/dnd/drop", function(source,nodes,iscopy){
  		var t = dojo.dnd.manager().target;
		ClearMsg();	
		if(t == source) return;
		if(t == cart)AddItems(t,nodes);
		if(t == shelf)SubstractItems(t,nodes);});

	dojo.subscribe("/dnd/start", function(source,nodes,iscopy){
  		var t = dojo.dnd.manager().target;
		ShowPrice(source,nodes);});

	dojo.subscribe("/dnd/cancel", function(){
  		ClearMsg();});

}

dojo.addOnLoad( init );
</script>

<div dojoType="dojo.dnd.Source" jsId="shelf" class="source" id="source1" accept="red,blue" singular=false>
    <img src="BLUE.png" class="dojoDndItem" dndType="blue" dndData="10" title="$10"/>
    <img src="BLUE.png" class="dojoDndItem" dndType="blue" dndData="3" title="$3"/> 
	.....    
</div>

<div dojoType="dojo.dnd.Source" jsId="cart" class="target" accept="red,blue" id="target1"></div>

Total Price (USD): <span id="cost">0.00</span><br/>

<b>Message: <span id="msg" style="color:blue"></span></b>

  • A global level javascript variable 'total' is used to store the updated price.
  • When the user starts dragging items, the 'ShowPrice' function gets called, which shows the total price of only the selected spheres.
  • The callback function for "dnd\drop" message does the following :
    • If the target and source are the same, exit and don't modify the total. This is because item has been dropped on same source from where it was dragged.
    • If target is cart, then call 'AddItems()' to add the prices of dropped items to the total.
    • If target is shelf, it means that items are being moved from cart to shelf, so call the 'SubstractItems()' function to deduct prices of those items from total.

This was a simple example of handling the DnD events to execute custom defined actions. So far we have covered basics, looked at using CSS for rich user interface and seen how to handle events. In next chapters we will learn about the 'node creator' function and build a very simple web based application to demonstrate use of DnD.

New Events in Dojo 1.0

Moveable implements three new events:

  • onMove, which implements the move itself
  • onMoving, which is called before onMove, so you have a chance to change something, for example, the new position of the move to implement some restrictions.
  • onMoved, which is called after the move, so you can update other objects after the move.

Events have better locality than topics: instead of getting called on every move and check if it is "the right" move, you can connect directly to events on the Moveable. Nevertheless topics are still supported.