2

Basically I have a list of draggable items and initially one droppable element for them to be dragged into. When an item is dragged into the droppable, the droppable is cloned (before the item is appended) and appended as a new droppable area.

Take a look at this stripped down fiddle: http://jsfiddle.net/DKBU9/1/ (omitted sortable())

HTML

<ul id="draggables">

    <li>foo1</li>
    <li>foo2</li>
    <li>foo3</li>

</ul>

<ul class="droppable new">

</ul>

JS

$('#draggables > li').draggable({
    appendTo: 'document',
    revert: 'invalid'
});

$('.droppable > li').draggable({
    appendTo: 'document',
    revert: 'invalid'
});

$('#draggables').droppable({
    accept: '.droppable > li',
    drop: function(event, ui) {
        ui.draggable.detach().css({top: 0,left: 0}).appendTo($(this));
    } 
});

$('.droppable').droppable({
    accept: '#draggables > li',
    drop: function(event, ui) {
        if($(this).hasClass('new')) {
            var clone = $(this).clone(true, true);
            $(this).removeClass('new').after(clone);
        }
        ui.draggable.detach().css({top: 0,left: 0}).appendTo($(this));    
    }
});

As you can see, the dragging and dropping works for the initial elements, but is not preserved in the clone. I thought clone(true, true) copied matched and child elements and their event handlers.

I even tried putting the above JS in a function and running that function in the drop events, but I got nothing.

Ultimately I want to be able to drag and drop between the "pool" list and the cloned lists and between the cloned lists themselves, as well as sort the items within the cloned lists.

Bobe
  • 2,040
  • 8
  • 29
  • 49

1 Answers1

3

Take a look at this fiddle.

You will need to set the droppable event handler again. I think that the clone(true) (i.e. with data and events) confuses things somewhat. Have a look at this answer. Specifically:

I think it is not very safe to copy an element that has a plugin applied to it, unless you are 100% sure that the way the plugin was designed and coded could support multiple DOM elements using the same plugin instance.

In this case it is simpler to just add the droppable event after clone.

The new function is:

function initDrop($element)
{
    $element.droppable({
        accept: '#draggables > li',
        drop: function(event, ui) {
            if($(this).hasClass('new')) {
                var clone = $(this).clone();                
                $(this).after(clone);
                $(this).removeClass('new');
                initDrop( clone );
            }
            ui.draggable.detach().css({top: 0,left: 0}).appendTo($(this));    
        }
    });
}

Also have a look at this question which also found that cloned item was not droppable (have a look at the workaround as well in case it is useful to you).

Community
  • 1
  • 1
acarlon
  • 16,764
  • 7
  • 75
  • 94
  • Works perfectly, thank you. I think I understand clone() a bit better now. I did read that part about plugins, but I kind of skimmed over it. This would be partly why my attempt to do a similar recursive function failed. Is it possible to then add sortable() onto this? I've just chained it on the end of the droppable() function, but draggable() takes precedent on the drag event. – Bobe Jan 07 '14 at 07:08
  • @Bobe - Happy to help. It is possible to have sortable() and droppable() working together. You might want to give it a go and post a new SO question if you have trouble with it. If you do, you can post the link in the comments here and I will take a look. – acarlon Jan 07 '14 at 07:25
  • I spent a good deal of time on it but just couldn't get the result I'm after. I've created a new question if you'd like to take a look: http://stackoverflow.com/questions/20986157/jquery-ui-make-draggable-element-sortable-within-droppable – Bobe Jan 08 '14 at 02:58