Search code examples
jqueryjquery-uijquery-ui-droppable

jQuery UI's greedy droppable not working as expected


I have a list of draggables than can be dropped inside a droppable and when this happens, the draggables are cloned and converted to droppables.

This new droppables are greedy but when they receive a draggable, both drop events are fired (the drop event from the draggable and the drop event from the droppable area)

What I'm doing wrong? I need the event to fire only once (from the new droppable)

Here's a fiddle: drag and drop an item into the red area, then drag another item and drop it into the item you already dropped. See the console log.

HTML

<div id="main_droppable"></div>

<ul>
  <li class="item" data-id="1">1</li>
  <li class="item" data-id="2">2</li>
  <li class="item" data-id="3">3</li>
  <li class="item" data-id="4">4</li>
  <li class="item" data-id="5">5</li>
</ul>

JS

$(".item").data("active", false);

$(".item").draggable({
    helper: "clone",
    appendTo: "#main_droppable",
    scroll: false,
    start: function(event, ui)
    {
        if($(this).data("active") == false)
        {
            $(this).fadeTo(100, 0.2);
        }
        else
        {
            return false;
        }
    },
    revert: function(is_valid_drop)
    {
        if(!is_valid_drop)
        {
            $(this).fadeTo(100, 1).data("active", false);

            return true;
        }
        else
        {
            $(this).data("active", true);
        }
    }
});

$("#main_droppable").droppable({
    drop: function(event, ui)
    {
        console.log("drop main");

        addNewItem(ui.helper);

        return false;
    }
});

function addNewItem($oldItem)
{
    var $newItem = $oldItem.clone(false).fadeTo(100, 1).data("active", true);

    $oldItem.remove();

    $newItem.draggable({
        containment: "parent",
    });

    $newItem.droppable({
        greedy: true,
        drop: function(event, ui)
        {
            console.log("drop item");

            $(this).fadeTo(100, 0, function()
            {
                var $originalItem = $("ul").find(".item[data-id=" + $(this).data("id") + "]");

                $originalItem.fadeTo(100, 1).data("active", false);

                $("#main_droppable").find(".item[data-id=" + $originalItem.data("id") + "]").remove();
            });

            addNewItem(ui.helper);
        }
    });

  $("#main_droppable").append($newItem);
}

CSS

#main_droppable
{
  border: 1px solid red;
  min-height: 50px;
}

.item
{
  display: inline-block;
  border: 1px solid blue;
  width: 25px;
  height: 25px;
}

Solution

  • Well...it had to do with a particular class...

    When I dropped the draggable and cloned it, the ui-draggable-dragging class stayed in place. So in order to make it work I had to remove it, then everything worked as expected.

    I change this line:

    var $newItem = $oldItem.clone(false).fadeTo(100, 1).data("active", true);
    

    Into this one:

    var $newItem = $oldItem.clone(false).fadeTo(100, 1).data("active", true).removeClass("ui-draggable-dragging");
    

    updated fiddle: https://jsfiddle.net/3118zjg1/1/