Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Draggable + Sortable - How to drag and drop between two scrollable lists

I would like to have two lists, Available Items and Selected Items, whereby Available Items are assigned to Selected Items via drag and drop. I require the Selected Items to be sortable, but not the Available Items. The challenge is that both lists can potentially contain a significant number of items, and therefore need to be scrollable.

Here is the jQuery I have thus far:

        <script type="text/javascript">
        $(function() {
            $( "#available > li" ).draggable({ 
                revert: 'invalid',
                connectToSortable: '#selected',
                containment: '#drag_container'
            });

            $( "#selected" ).sortable({
                axis: 'y',
                placeholder: 'ui-state-highlight'
            });
        });
    </script>

And the corresponding HTML:

            <div class="drag_container">
            <ul id="available" class="drag_column draggable">
                <li id="item1" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 1</li>
                <li id="item2" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 2</li>
                <li id="item3" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 3</li>
                <li id="item4" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 4</li>
                <li id="item5" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 5</li>
                <li id="item6" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 6</li>
                <li id="item9" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 9</li>
                <li id="item10" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 10</li>
            </ul>


            <ul id="selected" class="drag_column draggable sortable" style="margin-left: 20px;">
                <li id="item7" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 7</li>
                <li id="item8" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 8</li>
                <li id="item9" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 9</li>
                <li id="item10" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 10</li>
                <li id="item11" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 11</li>
                <li id="item12" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 12</li>
                <li id="item13" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 13</li>
                <li id="item14" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 14</li>
                <li id="item15" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 15</li>
                <li id="item16" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 16</li>
                <li id="item17" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 17</li>
                <li id="item18" class="ui-state-default"><span class="ui-icon ui-icon-arrow-4-diag"></span>Item 18</li>
            </ul>
            <div style="clear: both">&nbsp;</div>
        </div>

With the scrollable list requirement, however, I can't get the draggable behaviour to work elegantly (see the demo at http://pastehtml.com/view/1bsk6bt.html).

Once the item being dragged enters the Available Items list, it disappears behind the scrollable frame. I've tried the clone helper, and also tried playing around with containing divs, different overflow options, turning off the scroll option in jQuery, but cannot get it to work properly. I'm sure someone out there has accomplished something like what I'm aiming to do here and can save me some time? :)

Any help would be greatly appreciated!

like image 802
mwalsher Avatar asked Nov 05 '10 20:11

mwalsher


1 Answers

Whew! That was a fun one to fix.

The first problem, with the list scrolling forever horizontally, I fixed with some simple overflow changes in your CSS. I removed both of the overflow attributes from your .drag_column, and put an overflow: hidden in .drag_container.

.drag_container {
    width: 1000px;
    margin: 0 auto;
    position: relative;
    border: 1px solid black;
    position: relative;
    z-index: 1;
    overflow: hidden;
}

.drag_column {
    padding: 5px;
    width: 490px;
    height: 200px;
    float: left;
    position: relative;
}

Unfortunately, when I did that it created a position error when you moved your draggable from one list to another (it would shoot upwards, depending on which list item you chose). To fix this, I added the line "helper: clone" to your draggable creation function.

$( "#available > li" ).draggable({ 
    revert: 'invalid',
    connectToSortable: '#selected',
    containment: '#drag_container',
    helper: 'clone'
});

Once again, this created an undesirable effect. The clone helper makes it so the original list never has items deleted. To fix this, I had to manually create a function that would delete the old item. What I did was I added a start: function to your draggable object, that grabbed the object id and put it in a variable. Then I created a droppable object of your #selected list, and made a drop: function there. That drop function simply does a slideUp(100) on the object with the matching id. Note that I have a variable creation at the initiation of the script - this fixes a bug in IE.

var dragged = null;
$(function() {
    $( "#available > li" ).draggable({ 
        revert: 'invalid',
        connectToSortable: '#selected',
        containment: '#drag_container',
        helper: 'clone',
        start: function(ui, event) {
            dragged = $(this).attr('id');
        }
    });
    $( "#selected" ).droppable({
        drop: function(event, ui) {
            var ident = "#" +  dragged;
            $(ident).slideUp(100);
        }
    });

I posted a page with the full HTML at http://pastehtml.com/view/1by9nfd.html so you can play around if you want. Hope this helps!

like image 199
jwegner Avatar answered Oct 02 '22 10:10

jwegner