DigitalJoel

2011/02/23

jQuery Dragging a Table Row, Dropping a List Item

Filed under: jquery — Tags: , , , — digitaljoel @ 11:14 pm

I have a collection of survey questions. I’m using the jQuery datatables plugin to show those questions in a way that is sortable and filterable. The datatables plugin is awesome for this. You can look at the reference for the datatables plugin for more information.

Next, I wanted to be able to drag the question as represented in a table row into a list. The list needs to be orderable, because the order of the questions in the survey is important. This leads me to the conclusion that I need to use the jQuery Sortable functionality.

Here’s my problem. If I drag the table row and drop it on the ordered list, I end up with a list full of table rows. That’s not great. The key is in the reception of the dropped element in the sortable list. Let’s get to some source.

            // variables to hold the table and the list.
            var qTable;
            var newSurvey;

            // create the fancy datatable
            $(function() {
                // setup the datatable according to the docs at datatables.net
                // my table only has two columns, with the question text being in the first column.
                qTable = $('#questionTable').dataTable( {
                        "aoColumns": [
                                      { "asSorting": [ "desc", "asc" ] },
                                      { "asSorting": [ "desc", "asc", "asc" ] },
                                  ]
                        , "bJQueryUI": true
                    }
                );
                
                // Get all the table rows and make them draggable
                $(qTable.fnGetNodes()).draggable({
                    opacity: 0.7,
                    helper: function() {
                        var text = this.children[0].innerText;
                        var result = "<li id='"+this.id+"'>"+text+"</li>";
                        return result;
                    },
                    connectToSortable: '#newSurvey'
                });

                // setup the sortable ordered list
                newSurvey = $('#newSurvey');
                newSurvey.sortable({
                    beforeStop: function( event, ui ) {
                        var id = ui.helper.attr( "id" );
                        var text = ui.helper.text();
                        var li = "<li id='"+id+"'>"+text+"</li>";
                        $(ui.item).replaceWith( li );
                    }
                }).disableSelection();
                
            });

There are a couple of subtleties here that you probably would miss if I didn’t point them out to you.

First, this line:

$(qTable.fnGetNodes()).draggable({

Looks simple enough. This line adds the draggable functionality to all rows of the datatable. This was a key. If you use another selector, something like “#tableId tr” which you would think would work, you’ll be in trouble. That’s because if you change the data that is viewed in the table, i.e. by filtering, then the draggable functionality will be lost on the new rows that are shown. So, in order to apply it to ALL rows of the table, you must call the function supplied by the datatables plugin.

Next, the helper function in the draggable setup.

    helper: function() {
        var text = this.children[0].innerText;
        var result = "<li id='"+this.id+"'>"+text+"</li>";
        return result;
    },

The helper is what is going to be displayed to the user when they are dragging your table row. I didn’t really care about showing the second column, so here I convert it to an li. This conversion isn’t absolutely necessary, but I left it in for kicks. If you decide not to write your own helper, you can use a built in “clone” helper. This will leave the row in the table and clone it for what is dragged rather than removing it from the table when you drag it out.

Finally, the beforeStop function of the Sortable.

    beforeStop: function( event, ui ) {
        var id = ui.helper.attr( "id" );
        var text = ui.helper.text();
        var li = "<li id='"+id+"'>"+text+"</li>";
        $(ui.item).replaceWith( li );
    }

While we did the transformation in the helper of the draggable, the helper isn’t what is dropped in the sortable, the actual item is, which in our case, is still a tr. So, once again, I do the transformation. Since it’s easier to get the information out of the helper than out of the table row again, I used that here. It seems like I ought to be able to just get the text of the li in the helper, but I didn’t pursue that much further. Also, if you attempt to change the item to an LI in the draggable definition, then you may end up with LIs in your table. It could get ugly.

So, there you have it. You are no longer dropping TRs in your ULs. Your tables have TRs and your ULs have LIs.

One caveat. I attempted to upgrade from 1.4.4 to 1.5 of jquery core tonight and found that dropping into the list was broken if I dragged the item out of the top of the drop zone.

About these ads

2 Comments »

  1. Thanks, the return function from your helper to the beforeStop: event really helped me in a project I am working on. I have been working on getting the id of a conected sortable, have been searching on google for 4 days. Thanks for a great post.

    Comment by pingbullhenning — 2011/10/03 @ 12:46 pm

    • Glad it helped. I spent a considerable amount of time on this one and have already forgotten most of it so this entry was as much for me as anyone else. I only dabble in javascript when absolutely necessary.

      Comment by digitaljoel — 2011/10/03 @ 2:57 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 224 other followers