Search code examples
htmljquery-uijquery-ui-sortablejquery-ui-draggablejquery-ui-droppable

jQueryUI - how to drag from source box to two destination boxes, then get id of moved item and id of destination box


I'm trying to use jQueryUI draggable/droppable/sortable to move (not copy) items from a source box to either of the destination boxes. This is so the user can sort the items into the boxes they want.

  1. Then when they POST the page back to the server it will save their selection and what box they put the items into. So when an item is 'dropped' into one of the boxes, I need to somehow get the id of the dropped item and the id of the box it was put into. I'll store this in an array/object later.
  2. Would be handy if the user could order the items within the droppable boxes, but not critical. I do need them to line up nicely automatically though like how an unordered list is supposed to work. At the moment the items just drop anywhere in the destination boxes so all the items are all over the place inside the destination box.
  3. If the user changes their mind, they should be able to move the item back out of the destination box to the source box
  4. I have a shell of the code up below but it doesn't work and I can't seem to get the ids of the moved item or the destination id. I was attempting to use the new HTML5 data attributes but it doesn't appear to get anything out. My site is HTML5 so can use these new techniques.

Update: Got it working - full solution on JSfiddle and below:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>jQuery UI Source + Double Destination Demo</title>
    <link rel="stylesheet" href="../../themes/base/jquery.ui.all.css">
    <script src="../../jquery-1.7.1.js"></script>
    <script src="../../ui/jquery.ui.core.js"></script>
    <script src="../../ui/jquery.ui.widget.js"></script>
    <script src="../../ui/jquery.ui.mouse.js"></script>
    <script src="../../ui/jquery.ui.draggable.js"></script>
    <script src="../../ui/jquery.ui.droppable.js"></script>
    <script src="../../ui/jquery.ui.sortable.js"></script>
    <link rel="stylesheet" href="../demos.css">
    <style>
        h1 { padding: .2em; margin: 0; }
        #destinationA, #destinationB { width: 200px; float: left; }

        /* style the list to maximize the droppable hitarea */
        #destinationA ol, #destinationB ol, #source ul { margin: 0; padding: 1em 0 1em 3em; background-color: #f7f7f7; }
    </style>

    <script>
    $(function()
    {
        $( "#source li" ).draggable({
            appendTo: "body",
            helper: "clone"
        });
        $( "#destinationA ol, #destinationB ol, #source ul" ).droppable(
        {
            activeClass: "ui-state-default",
            hoverClass: "ui-state-hover",
            accept: ":not(.ui-sortable-helper)",
            drop: function( event, ui )
            {
                // Get id of the item that was moved
                var itemIdMoved = ui.draggable.data('item-id');
                var itemName = ui.draggable.data('item-name');

                // Get id of the current destination (the item is dropped into the ul tag so we need to go up a level to get the div id)
                var destinationId = $(this).parent().attr('id');

                // Move the draggable into the destination box (actually moves the original li element including data attributes)
                ui.draggable.appendTo(this);

                // Debug
                console.log('item ' + itemName + ' (id: ' + itemIdMoved + ') dropped into ' + destinationId);
            }
        }).sortable(
        {
            sort: function()
            {
                // gets added unintentionally by droppable interacting with sortable
                // using connectWithSortable fixes this, but doesn't allow you to customize active/hoverClass options
                $( this ).removeClass( "ui-state-default" );
            }
        });
    });
    </script>
</head>
<body>
    <h1 class="ui-widget-header">Source</h1>    
    <div id="source">
        <ul>
            <li data-item-id="1" data-item-name="One">Item 1</li>
            <li data-item-id="2" data-item-name="Two">Item 2</li>
            <li data-item-id="3" data-item-name="Three">Item 3</li>
            <li data-item-id="4" data-item-name="Four">Item 4</li>
        </ul>
    </div>

    <div id="destinationA">
        <h1 class="ui-widget-header">Destination A</h1>
        <ol>

        </ol>
    </div>

    <div id="destinationB">
        <h1 class="ui-widget-header">Destination B</h1>
        <ol>

        </ol>
    </div>
</body>
</html>

Solution

  • From the documentation:

    In the callback, $(this) represents the droppable the draggable is dropped on. ui.draggable represents the draggable.

    So i guess you could just do that:

    $('#destinationA ul, #destinationB ul').droppable(
    {
        drop: function(event, ui)
        {
            // Get id of the item that was moved
            var idMoved = $(this).data('itemid');
            console.log(idMoved);
    
            // How to get the destination ID that the item was dropped to?
            var idDropped = this.id;
            console.log(idDropped);  // "destinationA" or "destinationB"
        }
    })