ColdFusion Flash Form Slush Select and Grid

With a little effort I adjusted some of my code to handle drag and drop capabilities of both select boxes and data grids on the same form.

I reuse the event listener functions for each of the objects. Press the refresh data button to load the grids and drag away!!!

Live Example

***For those having issues with copying and pasting the code here is the download:***
Code

***New Code added that checks for uniqueness in the destination grid and select based off of a key field (hope this helps Brian):***
Code

Live Example

The Code:

<cfform name="slushForm" format="Flash" onload="formOnLoad()" width="800" timeout="500">
<cfformitem type="script">
//Drag Drop enable for grids var overSourceItem:Boolean = false;
var overTargetItem:Boolean = false;

//Reference the grids var gridSource:Object = {};
var gridDestination:Object = {};

function addData()
{
//Add some data to the source grid    grid1.removeAll();
   grid2.removeAll();
   select1.removeAll();
   select2.removeAll();
grid1.addItem({lastName:"Smith",firstName:"Jane",phone:"(555) 555-1234"});
   grid1.addItem({lastName:"Jones",firstName:"Jen",phone:"(555) 555-5678"});
   select1.addItem({data:1, label:"Smith, Jane"});
   select1.addItem({data:1, label:"Jones, Jen"});
}
function formOnLoad()
{      
   grid1.dragEnabled=true;
   grid1.multipleSelection=true;
   grid1.addEventListener('dragEnter', doDragEnter);
   grid1.addEventListener('dragOver', doDragOverSource);
   grid1.addEventListener('dragExit', doDragExitSource);
   grid1.addEventListener('dragDrop', doDragDropDGSource);
   grid1.addEventListener('dragComplete', doDragCompleteDGSource);   
   
   grid2.dragEnabled=true;
   grid2.multipleSelection=true;
   grid2.addEventListener('dragEnter', doDragEnter);
   grid2.addEventListener('dragOver', doDragOverDest);
   grid2.addEventListener('dragExit', doDragExitDest);
   grid2.addEventListener('dragDrop', doDragDropDGDest);
   grid2.addEventListener('dragComplete', doDragCompleteDGDest);
   
   select1.dragEnabled=true;
   select1.multipleSelection=true;
   select1.addEventListener('dragEnter', doDragEnter);
   select1.addEventListener('dragOver', doDragOverSource);
   select1.addEventListener('dragExit', doDragExitSource);
   select1.addEventListener('dragDrop', doDragDropDGSource);
   select1.addEventListener('dragComplete', doDragCompleteDGSource);   
   
   select2.dragEnabled=true;
   select2.multipleSelection=true;
   select2.addEventListener('dragEnter', doDragEnter);
   select2.addEventListener('dragOver', doDragOverDest);
   select2.addEventListener('dragExit', doDragExitDest);
   select2.addEventListener('dragDrop', doDragDropDGDest);
   select2.addEventListener('dragComplete', doDragCompleteDGDest);
}

function doDragEnter(event) {
event.handled = true;
}
function doDragExitSource(event) {
_root.overSourceItem = false;
event.target.hideDropFeedback();
}

function doDragExitDest(event) {
_root.overTargetItem = false;
event.target.hideDropFeedback();
}

function doDragOverSource(event) {
_root.gridSource = event.target;
if (_root.gridDestination.dataProvider.length > 0)   
{
_root.overSourceItem = true;
event.target.showDropFeedback();
if (Key.isDown(Key.CONTROL))
event.action = mx.managers.DragManager.COPY;
else if (Key.isDown(Key.SHIFT))
event.action = mx.managers.DragManager.LINK;
else
event.action = mx.managers.DragManager.MOVE;
}
}

function doDragOverDest(event) {
_root.gridDestination = event.target;
if (_root.gridSource.dataProvider.length > 0)   
{
_root.overTargetItem = true;
event.target.showDropFeedback();
if (Key.isDown(Key.CONTROL))
event.action = mx.managers.DragManager.COPY;
else if (Key.isDown(Key.SHIFT))
event.action = mx.managers.DragManager.LINK;
else
event.action = mx.managers.DragManager.MOVE;
}
}

function doDragDropDGSource(event) {
doDragExitDest(event);
var dragItems = event.dragSource.dataForFormat('items');
var dest = event.target;
var dropLoc = dest.getDropLocation();
var destParentNode = dest.getDropParent();
dest.addItemsAt(dropLoc,dragItems);
}

function doDragDropDGDest(event) {
doDragExitSource(event);
var dragItems = event.dragSource.dataForFormat('items');
var dest = event.target;
var dropLoc = dest.getDropLocation();
var destParentNode = dest.getDropParent();
dest.addItemsAt(dropLoc,dragItems);
}

function doDragCompleteDGSource(event){
var dest = event.target;
var dropLoc = dest.getDropLocation();
var destParentNode = dest.getDropParent();
var selectedIn:Array = event.target.selectedIndices;
//descending sort to remove items that have been dropped into target grid selectedIn.sort(16|2);

if (_root.overTargetItem)
{
for(var i = 0; i < selectedIn.length; i++){
//add the selected items _root.gridDestination.dataProvider.addItem(event.target.selectedItems[i]);
}
   
   for(var i = 0; i < selectedIn.length; i++){
//remove this item event.target.dataProvider.removeItemAt(selectedIn[i])
}
}
_root.overTargetItem = false;
_root.gridDestination.hideDropFeedback();
}

function doDragCompleteDGDest(event){
var dest = event.target;
var dropLoc = dest.getDropLocation();
var destParentNode = dest.getDropParent();
var selectedIn:Array = event.target.selectedIndices;
//descending sort to remove items that have been dropped into target grid selectedIn.sort(16|2);
if (_root.overSourceItem)
{
for(var i = 0; i < selectedIn.length; i++){
//add the selected items _root.gridSource.dataProvider.addItem(event.target.selectedItems[i]);
}
for(var i = 0; i < selectedIn.length; i++){
//remove this item event.target.dataProvider.removeItemAt(selectedIn[i])
}
}
_root.overSourceItem = false;
_root.gridSource.hideDropFeedback();
}

</cfformitem>
<cfformgroup type="accordion">
<cfformgroup type="page" label="Slush Grid">
<cfformgroup type="horizontal">
   <cfformgroup type="hbox">
    <cfformitem type="text" height="15" style="font-weight:bold">Source Grid</cfformitem>
    <cfgrid name="grid1" rowheaders="false" height="85">
      <cfgridcolumn name="lastName" header="Last" bold="no">
      <cfgridcolumn name="firstName" header="First" bold="no">
      <cfgridcolumn name="phone" header="Phone" bold="no">
    </cfgrid>
   </cfformgroup>
   <cfformgroup type="hbox">
    <cfformitem type="text" height="15" style="font-weight:bold">Destination Grid</cfformitem>
    <cfgrid name="grid2" rowheaders="false" height="85">
      <cfgridcolumn name="lastName" header="Last" bold="no">
      <cfgridcolumn name="firstName" header="First" bold="no">
      <cfgridcolumn name="phone" header="Phone" bold="no">
    </cfgrid>
   </cfformgroup>
</cfformgroup>
</cfformgroup>
<cfformgroup type="page" label="Slush Select">
<cfformgroup type="horizontal">
   <cfformgroup type="hbox">
    <cfformitem type="text" height="15" style="font-weight:bold">Source Select</cfformitem>
    <cfselect name="select1" size="3" multiple="yes" />
   </cfformgroup>
   <cfformgroup type="hbox">
    <cfformitem type="text" height="15" style="font-weight:bold">Destination Select</cfformitem>
    <cfselect name="select2" size="3" multiple="yes" />
   </cfformgroup>
</cfformgroup>
</cfformgroup>
</cfformgroup>
<cfinput type="button" name="btnAddData" value="Refresh Data" onClick="addData();">
</cfform>

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
very nice.
# Posted By Patrick Whittingham | 4/1/06 12:37 PM
Looks great...but... it doesn't seem to matter whether I hold down ctrl or shift - the selections just move from one grid to another and don't copy.
# Posted By Tom | 4/9/06 7:26 AM
Not sure I understand the issue Tom. What are you looking for in the way of copying functionality? Are you wanting the items selected to stay in the originating grid when copying? If so, that can be coded for. This just gives the coder looking to get drag and drop working a head start. I will soon be posting code that checks for unique values as well, If you would like to see the grids do something different, please let me know and I'll try and get you something a bit more refined.
# Posted By Jeff Bouley | 5/1/06 9:47 AM
your example works fine for me using the live example link. but when i run the posted code on my server, it doesnt function properly.

Namely: dragging to the right side grid makes the record vanish from both grids.

and pressing the refresh data button adds the 2 records in addition to what ever remains in the left side instead of replacing it.

did you post the same code that you use in your live example?

Thanks,
Chris
# Posted By chris jones | 5/12/06 1:55 PM
/\ never mind the above comments... when i copied and pasted your code, a few the lines got concatenated into comment lines...

now it works great!
# Posted By chris jones | 5/12/06 2:02 PM
/\ never mind the above comments... when i copied and pasted your code, a few the lines got concatenated into comment lines...

now it works great!
# Posted By chris jones | 5/15/06 9:27 AM
Hi,

How could I use this code to re-order a simple select list?

thanks.

rick
# Posted By Rick Root | 7/25/06 11:28 AM
Rick,

I'm not clear on what exactly you are asking. When you say re-order do you mean sort?

--Jeff
# Posted By Jeff Bouley | 7/26/06 5:24 PM
i think what rick is lookinng for is that when the items from the source are moved to the destination he, as well as I, would like to be able to drag the items in the destination to a new order in that same destination grid. If i click and hold on item 3 in dest grid and release in pos 0 item 3 should be moved to pos 0 and the other items shifted to their new positions accordingly
thanks...
# Posted By james | 8/11/06 11:20 AM
Hi,

Your explain why don't work in my server?

I install updater 2 to Colfusion and it doesn't work....!

Please help me...!

I have the same problem that it:

&amp;amp;amp;amp;quot;your example works fine for me using the live example link. but when i run the posted code on my server, it doesnt function properly.

Namely: dragging to the right side grid makes the record vanish from both grids.

and pressing the refresh data button adds the 2 records in addition to what ever remains in the left side instead of replacing it.&amp;amp;amp;amp;quot;

did you post the same code that you use in your live example?&amp;amp;amp;amp;quot;
# Posted By kike | 8/14/06 12:54 PM
There have been a coule of issues with the documented code no formatting properly in ides such as DreamWeaver. You need to check the actionscript for malformatted code. Usually happens on a comment line and please don't yell at me in future requests 8-).
# Posted By Jeff Bouley | 8/14/06 8:33 PM
I have added a code link due to the issues associated with malformatted code. The link is above the code block.
# Posted By Jeff Bouley | 8/16/06 12:52 PM
This example works dragging from one grid to another grid. Could this functionality also work to drag from say grid1 to either grid2 or grid3 or grid4?

If so, what parts of the code would need to be changed? I've tried this in an example and I can drag the item, but it disappears when I drop it and doesn't remove itself from the list.

Thanks!
# Posted By Tobin Lewis | 8/23/06 9:56 AM
Yes, you could definitely drag to multiple grid destinations, but would need to add them as destination grids (like grid2 under formOnLoad func). Should be very straightforward. Sorry for the delayed response.
# Posted By Jeff Bouley | 8/31/06 8:57 AM
Great Code!

I just ask myself how one can achieve that awful onClick hiding of the hbox ?
How do you do that - Can you give me a hind?

Thx in Advance, Michael
# Posted By Michael Oberle | 9/13/06 11:17 AM
This code is great and works like a charm. However, I'm running into a problem processing the form. When I try and do a cfgridupdate on the destination grid, nothing happens. So I tried doing a cfdump of the form and all the columns from both the source and destination grids come through as empty.

Did you have this problem and/or do you have any examples of the code you use on the results page?

Thanks in advance.
Catherine
# Posted By Catherine | 12/11/06 3:27 AM
I am having the same issue as Catherine, i can not get the destination grid data to update or insert into a table. Any help would be great.

Thanks,

Jacob
# Posted By Jacob | 12/26/06 11:19 AM
I use remoting to send the data back to the database. You can access the contents of the select box or grid with actionscript and then pass the data back to a cfc function.
# Posted By Jeff Bouley | 1/5/07 12:19 PM
Hi Jeff,
Lovin the slush! I got it working correctly pushing data over as per your example. We have gone one step further and created an edit functionality with the second box. We found that when you fill the grid with data that it works okay, but when you submit it to the CFC the form is blank.

Below is the code that we are using.
We are doing a sort by on one of the columns as soon as we edit it, it works, however when you try and remove an item from the list it fails.

Have I gone to far with this code.

   &lt;cfgrid name=&quot;gridSource&quot; rowheaders=&quot;false&quot; height=&quot;85&quot;&gt;
                         &lt;cfgridcolumn name=&quot;PostCodeID&quot; header=&quot;PostCodeID&quot; bold=&quot;no&quot;&gt;
                        &lt;cfgridcolumn name=&quot;Postcode&quot; header=&quot;Postcode&quot; bold=&quot;no&quot;&gt;
                         &lt;cfloop query=&quot;getPostCodes&quot;&gt;
                      &lt;cfgridrow data =&quot;#PostcodeID#,#Postcode#&quot;&gt;
                      &lt;/cfloop&gt;
                     &lt;/cfgrid&gt;
                     &lt;cfformitem type=&quot;text&quot; height=&quot;15&quot; style=&quot;font-weight:bold&quot;&gt;Postcodes you want the Representative to relate to.&lt;/cfformitem&gt;
                     &lt;cfgrid name=&quot;gridDestination&quot; rowheaders=&quot;false&quot; height=&quot;85&quot; selectmode=&quot;edit&quot; &gt;
                        &lt;cfgridcolumn name=&quot;PostCodeID&quot; header=&quot;PostCodeID&quot; bold=&quot;no&quot;&gt;
                        &lt;cfgridcolumn name=&quot;Postcode&quot; header=&quot;Postcode&quot; bold=&quot;no&quot;&gt;
                        &lt;cfgridcolumn name=&quot;sortby&quot; header=&quot;Order&quot; bold=&quot;no&quot; &gt;
                        &lt;cfgridcolumn name=&quot;pfid&quot; header=&quot;pfid&quot;&gt;
                        &lt;cfloop query=&quot;getRepPostCodes&quot;&gt;
                           &lt;cfgridrow data=&quot;#PostCodeID#,#Postcode#,#sortby#,#pfid#&quot;&gt;
                        &lt;/cfloop&gt;
                     &lt;/cfgrid&gt;
# Posted By Jeremy | 1/16/07 5:04 PM
This is a real nice bit of coding. I've implemented it on a im working on.
I do have a question, do you know how to make it so the source wil copy into the destinationGrid but not duplicate. I think It could be possible with a little if then statement, but Im not sure how to approach it.

I got rid of this bit of code:
for(var i = 0; i < selectedIn.length; i++){
//remove this item
event.target.dataProvider.removeItemAt(selectedIn[i]);
and that make it's copy without removing, but if you copy it again it will duplicate.

Have any ideas on how to prevent that?
Thanks.
# Posted By Brian | 2/25/07 10:52 PM
Hey Brian,

There is two ways to accomplish that. Either check for the values already added when populating the source grid or on completion of your drag loop over an existing key field in the destination grid dataprovider to check if it is there. If the item is already added then make the drag fail returning the item to the source or removing entirely.

Always two approaches in this scenario, either don't let the user do something that will fail or let the user do something that does cause a failure. I tend to go with not allowing the user to do something that will fail in the system when possible unless there is a significant performance hit in doing so. If I have time I believe I implemented the behavior you are requesting. If I get time I'll submit another reply to the blog entry.
# Posted By Jeff Bouley | 2/26/07 12:27 PM
Thanks Jeff, I really appreciate your help.
# Posted By Brian | 2/26/07 5:19 PM
Brian,

I added what I think you need above, you can view the demo and download the zip. To get the multiple (same value scenario working just click the refresh search button after your first drag out of the search lists). Let me know how it works for you.
# Posted By Jeff Bouley | 2/27/07 1:07 PM
Jeff, that sure does help! This is exactly what I've been struggling to achieve. Im impressed with willingness to share your work, and even more in awe of what you've achieved here. Hat's off to you, and thanks again.
# Posted By Brian Scott | 2/28/07 12:41 AM
Brian, good to hear.

Jeremy, sorry for the late reply... schedule has been tight. Can you send me your source?
# Posted By Jeff Bouley | 2/28/07 9:24 AM
FYI, Becasue I commented out these sections:
<!---- for(var i = 0; i < selectedIn.length; i++){
//remove this item from Source
event.target.dataProvider.removeItemAt(selectedIn[i]);
} ---->
and
<!----for(var i = 0; i < selectedIn.length; i++){
//add the selected items to Source
_root.gridSource.addItem(event.target.selectedItems[i]);
}--->

I ended up getting a bug when you selected an item in the destination grid, and started to drag it, it would remove it on release, regardless of whether or not i was still over the destination grid.
SO I changed:
//descending sort to remove items that have been dropped into target grid
selectedIn.sort(16|2);            
if (!overDestinationItem) {
to:
//descending sort to remove items that have been dropped into target grid
selectedIn.sort(16|2);            
if (overSourceItem) {

It was this way in your original code, but had been changed in the latest zip.
# Posted By Brian | 3/5/07 7:52 PM
Hey Brian,

I got you, yes, it was coded that way due to customer request. It was changed from the initial example. Sorry for any confusion there. The only time my example code would send it back to the orginating grid was if they were over said grid. Thanks though, and glad to see you are making sense of the code 8-).
# Posted By Jeff Bouley | 3/8/07 2:43 PM
YES
# Posted By John GAG | 4/16/08 5:10 PM
How do you pass a variable from the cfformgroup to a query? thanks
# Posted By John GAG | 4/16/08 5:11 PM
Absolutely phenomenal! ...I'm having the worst time trying to get an onChange event to fire once an item is dropped into the destination grid. Any ideas?
# Posted By CPD | 4/17/08 12:48 PM
@JohnGAG, are you remoting? Hope so.

@CPD this approach is rather procedural in nature. You would have to dispatch a defined event if onChange is not firing when the item is added to the grid. onChange fires when a selected item changes, not necessarily when an item is added.
# Posted By Jeff Bouley | 4/17/08 8:51 PM
Thanks. I added _root.calculateTotal() (calculateTotal() being the desired function for onChange) to the doDragComplete functions for the desired effect.
# Posted By CPD | 4/18/08 8:46 AM
@CPD, when you're trying to figure out if an event handler is firing display an alert like in javascript. Always helps to point you to where you are in the code and validate whether your expected results are occuring.
# Posted By Jeff Bouley | 4/20/08 9:01 AM
Hi, i want to be able to drag,clone the row thats being dragged and drop to the next row in the table. how to do it? I want the destination to be the same table but new row. can someone help?
# Posted By sneha | 7/29/08 4:46 PM
When I run the Live Example in the Google Chrome browser the person I drag from left to right just disappears into the right box.
# Posted By Scott | 1/29/09 5:23 PM
Can someone give me a snippet of code how to put the rows of the destination grid in a sql table on submitting the form, please? Now I get only empty rows.

Thanks,

Alex
# Posted By Alex | 5/19/09 8:23 AM
Nice piece of work, but since it looks like it is not possible to submit the added rows from the destination grid to a next form or a database I don't see the value of it.
# Posted By Andreeke | 7/7/09 2:46 AM
@Andreeke,

You can loop over the contents of the destination grid and submit the data back to the db via remoting call. I recommend you look into AS2 on how to retrieve data from a data provider for a grid, etc. Good luck!
# Posted By Jeff Bouley | 7/7/09 8:36 AM
I know these comments are a bit old now, but to Andreeke and Alex:

I rely on the &quot;I,D,U&quot; CFGRID.ROWSTATUS.ACTION annotations for submitted grid data in order to perform some complex transactions hitting multiple tables that also depend on other form elements. I've accomplished this by replacing (in keeping with this example):

gridDestination.dataProvider.addItem(event.target.selectedItems[i]);

with :

GridData.insertRow(gridDestination);
_root.gridDestination.dataProvider.editField(_root.gridDestination.selectedIndex, 'mapped target field 1 name here', event.target.selectedItems[i]['mapped source field name 1 here']);
_root.gridDestination.dataProvider.editField(_root.gridDestination.selectedIndex, 'mapped target field 2 name here', event.target.selectedItems[i]['mapped source field name 2 here']);
You can lose the &quot;_root&quot; by declaring it in formonload. This is not as dynamic as it requires you to hard code your grid-to-grid column mappings, but by the same token, it allows you to have source and target grids that don't need to have identical columns. More importantly, the data will be present in your target grid when the form is submitted.

Kudos to Jeff again, as we use several variations of this quite extensively...

Thanks,
Chris
# Posted By CPD | 1/27/10 11:56 AM

Copyright Strikefish, Inc., 2005. All rights reserved.