This space is available to any ComponentArt employee to write about anything.

New Grid Feature: Item Drag and Drop

As of Web.UI 2006.2, Grid has a useful new feature: item drag and drop. For some time, many of you have been asking for such a feature, for many different reasons. Some wanted to be able to drag Grid items to and from a TreeView, others wanted to be able to re-order them, or to drag them to other external containers.

Since we don't yet have an example which takes advantage of this new feature, I thought I'd provide a brief overview of how it's used:

1. Set ItemDraggingEnabled to true

This enables dragging functionality - you can now drag a Grid item (row). By default, the item you drag will look like a copy of the Grid item, but you can use the ItemDraggingClientTemplateId and ItemDraggingCssClass properties to modify the appearance of the item as it is dragged.

2. Set the ExternalDropTargets property

This property is of type string and should be set to a comma-delimited list of potential drop target IDs. These can be ComponentArt control IDs or DOM element IDs. If you wanted to be able to drop Grid items to TreeView with ID "TreeView1" and a DIV with ID "dropTargetDiv", you would set ExternalDropTargets to "TreeView1,dropTargetDiv".

3. Set the ItemExternalDrop client event handler in the ClientEvents block

For instance:

<ComponentArt:Grid runat="server" id="Grid1" ... >
  ...
  <ClientEvents>
    <ItemExternalDrop EventHandler="Grid1_onItemExternalDrop" />
  </ClientEvents>
</ComponentArt:Grid>

4. Define the handler

For instance:

function Grid1_onItemExternalDrop(sender, eventArgs)
{
  var draggedItem = eventArgs.get_item();
  var targetControl = eventArgs.get_targetControl();
  var target = eventArgs.get_target();

  // perform logic
}

In this example, draggedItem would be the GridItem that was dragged. The variable targetControl would be set to the target client control (if the target is one), like a TreeView or a Grid. The target would be either a DOM element, in the case that the drop target was a simple DOM element, or a more abstract object, such as a TreeViewNode, if the target was a TreeView. You can then use the Web.UI client-side API to perform any custom logic you require.

While seemingly complicated, we feel that this kind of approach is general enough to cover all desired scenarios, yet simple enough to result in clean and readable code in most real-world applications.

As always, we love to hear feedback from you, which help us to evolve this feature in useful ways. 

Have fun!

 

Share this post: email it! | bookmark it! | digg it! | reddit!

Posted by: Milos
Posted: Wednesday, November 22, 2006 9:44 AM


Comments

Jeff Hagen said:

Very NICE! One question, what code would I use to reorder on the same grid?
# November 22, 2006 4:13 PM

Milos said:

First, you would set "Grid1" as an ExternalDropTarget on Grid1, so you can drop its items onto itself. Then, you would use something like the following for the drop handler: function Grid1_onItemExternalDrop(sender, eventArgs) { var draggedItem = eventArgs.get_item(); var targetItem = eventArgs.get_target(); var targetGrid = eventArgs.get_targetControl(); // We can now use this information to move the draggedItem to the place of the targetItem. You can do so on the server or the client. Here's how to do so on the client (note that this uses a couple of undocumented properties): // Get the GridTable and the index we want to move the item to var table = targetItem.get_table(); var index = targetItem.get_index(); // We operate on the raw data array, first removing the item from its original position, then inserting it into the desired one table.Data.splice(draggedItem.get_index(), 1); table.Data = table.Data.slice(0, index).concat([draggedItem.Data]).concat(table.Data.slice(index)); // Re-draw the grid targetGrid.render(); } Note that this uses some undocumented/unsupported code to modify the order of items on the client by operating on the raw data array. Unfortunately, this is necessary until we expose a more abstract API for manipulating this data.
# December 1, 2006 7:10 AM

Steve Craze said:

Hey Milos, Thats awesome! This control justs gets better and better. I did have a little trouble with that script though - it works most of the time, but occasionally if you try and drop the second grid item onto the first but only maybe a third/half way up the item (it has to be in the right spot - I think when the pointer of the mouse is right on/just above the dividing horizontal grid line), it seems to generate five or six loops of script errors - 2 x 'offsetParent is null or not an object' and 1 x 'offsetWidth is null or not an object', before looping through them again...till IE hangs on me, or will ask me later to abort the script. The line in the resource file is (with debugging on): while(qzgx.offsetParent!=null ... I think this functionality is brilliant - if you have any solutions or suggestions, that would be awesome! Thanks, Steve
# December 12, 2006 3:32 PM

Klaas said:

Great, ive been looking for functionality like this for quite some time. It seems to work, however, if i specify a ClientTemplate for the drag item (Since I dont want the whole row to be dragged.) it gets drawn from the upper left corner of the grid row. So when I try and drag a row by grabbing it in the lower right corner the dragtemplate (an icon in my case) is 400-500 px to the left of the cursor. Is there any way to get the template to draw itself at the cursors position? Thanks. Klaas.
# January 3, 2007 8:09 AM

Jeff Hagen said:

Thanks for the example, Milos.

I'm still struggling with one thing. When I set ExternalDropTargets to the id of the grid or the ClientID of the grid (ie, "Grid1" or "ctrl_100_Grid1"), I get the JavaScript error

"'ComponentArt_TreeView' is undefined"

upon dropping. If I set the drop target to the ClientID + "_dom" then it works fine, but the eventArgs.get_target() is a TD tag (not a GridItem).

# January 5, 2007 4:10 PM

Jeff Hagen said:

I found the problem. There is a line of code that says

if (xxx instanceof ComponentArt_TreeView)

but since ComponentArt_TreeView object is not defined anywhere, it barfs. So the work around is to just define an object

ComponentArt_TreeView = function () {alert("FROGS");}

Now it works, but I get an infinite loop in IE7 if I drag the GridItem to the header or footer of the grid with an error that says "offsetParent is null or not an object.

# January 5, 2007 5:06 PM

Klaas said:

And I still havent found a good solution to the problem I mentioned above. Anyone? I tried posting this on the forum aswell, but I guess no one knows.
# January 15, 2007 2:28 AM

Milos said:

Thanks for your feedback, everyone! These issues should be resolved in the next service pack build, which we hope to release in the next few days.

# January 18, 2007 9:47 AM

Klaas said:

I like this. Well, i got it to work by setting the css class of the layer to a alpha value of 50%. Anyway, having a context menu on the grid at same time messes everything up. Im looking forward to the service pack! Thanks.
# January 22, 2007 7:32 AM

Chris Williams said:

I'm trying to drag a file item onto a grid that already has a datasource. If the grid doesnt have a datasource, I can drag and drop the file onto it no problem, and I see the filename/path where I dropped it. Perfect. But since this grid has a datasource, which happens to be empty, there are no visible rows and I can't seem to get filedrop to happen. Any thoughts?
# February 20, 2007 1:40 PM

Jimmy said:

How do I disable dragging on a right click?
# February 26, 2007 12:35 PM

Is it possible to dreg multiple items at once said:

Is it possible to dreg multiple items at once? Thank you Dragos
# April 25, 2007 11:42 AM

Paddy said:

How do we set the CSS class for a column header ?
# May 9, 2007 10:30 PM

Louis De Grazia said:

I got this to work perfectly! Thanks for posting this!
# June 26, 2007 2:16 PM

Ranjit said:

Hay Its cool.......But I dont want the values of some columns to be changed. Like Suppose I have 10 columns in the grid then Out of those 10 columns I just want to swap the values of particularly two columns. Rest of the columns need to have the same value. as before dragging........If possible please mail at ranjithota@gmail.com
# October 8, 2007 8:08 AM

satya said:

i want to add 2 buttons . when i select a row from the first grid and clicking on the first button , then it should added into the second, and viceversa by second button. so what is the javascript code to do like this using client side.
# October 10, 2007 3:14 AM

Dhaval Heruwala said:

Hi, That was indeed a nice article, My grid is behaving the same way while dragging. Now there are few controls like checkbox and a dropdown on every record of my grid. I dont want them to be displayed while dragging. How can I achieve this?
# March 26, 2008 1:30 AM

Karan said:

How can we perform the task of dragging multiple items?
# June 16, 2008 3:06 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Blogs On This Site
Thoughts on web user interfaces and component development.
Ramblings of a web control developer.
Web.UI news and more
Next weeks guest: A dog and a baby dog!
I'm in your base, killing your dudes.
Absurdity is it's own message.
Musings of an ex Java developer
im in ur page, hackin ur codez
ComponentArt in the Community
... and the program ran happily ever after.

This Blog