Matías Cánepa
Matías Cánepa

Reputation: 5974

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;
}

Upvotes: 3

Views: 431

Answers (2)

Mat&#237;as C&#225;nepa
Mat&#237;as C&#225;nepa

Reputation: 5974

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/

Upvotes: 2

airudah
airudah

Reputation: 1179

I think the dragables actually become greedy but the #main_droppable event still gets triggered because:

When you place another .item element on top of another, the intended action for dropping a .item into another .item gets triggered.

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

but this original element gets removed further down the code anyway..

    $(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();
        ...

You're effectively replacing the original item with the new one hence the #main_droppable event getting triggered.

I can't say I know how to fix the unintentional side effect without changing your intended behaviour, but hopefully you have a better clue as to why the greedy attribute seems to not work.

Upvotes: -1

Related Questions