Search code examples
jqueryjquery-uidraggablejquery-ui-sortablejquery-ui-draggable

Jquery : Draggable items linked between SortableList and DroppableArea clone issue


I'm working on a panel made of 2 parts :

  • A list : containing all my widgets, and I'd like every widget to be draggable and sortable.

  • An area : containing an image where I want to drop my widgets on (and save their position later on) : So I need my widgets to be droppable and draggable.

I'm trying to do that behavior with JQuery UI. On top of that, I'd like to be able to drag my widgets from the list to the area, and if I want, drag them back to the list.


EDIT : https://jsfiddle.net/Tenmak/jzmsatrg/ (new link)

var myImageSlot = $("#image_slot").droppable({
    accept: ".listItem",
    drop: function(ev, ui) {
      console.log('dropped');

      if (ui.draggable.hasClass("ontray")) {
        var cloneTile = ui.draggable.clone()
            .removeClass("ontray")
          .removeClass("ui-sortable-handle")
          .show();
        myImageSlot.children(".itemsContainer").append(cloneTile);
        var dropx = ui.offset.left - myImageSlot.offset().left;
        var dropy = ui.offset.top - myImageSlot.offset().top;

        cloneTile.css({
          "left": dropx + "px",
          "position": "absolute",
          "top": dropy + "px"
        });
        setTileDraggable(cloneTile);
        ui.helper.remove();
        ui.draggable.remove();
      }
    }
  }).disableSelection();

By setting absolute position to the draggable item when outside of the list, the wanted behavior is there, and the animation is smoother, but sometimes, it gets duplicated most probably because of the clone() method not working correctly.

Is there any way to correct this buggy behavior ? Should I proceed differently ? Any help would be really nice, I feel I'm getting there but some tips or anythins would really be helful. N.B : I'm opening a bounty as soon as I can because I really need this.


Solution

  • I hope I have fixed the issue you had with the duplicates when doing the clone after the drop.

    The reason I found is, its getting cloned twice when you quickly drag and drop items between the containers since the drop event called twice for some reason as the fastest movements would have triggered it.

    To fix this, I setup an index to each draggable item on the load with help of data attribute and checking the same when appending the item to the container for any of the same index exists already to avoid the duplication.

    Then I tested this a lot and can't able to replicate the issue no more. So I hope it solved the issue but anyways I will need you to check and confirm :-)

    Here is the updated fiddle link,

    https://jsfiddle.net/balasuar/jzmsatrg/4/

    The fix I did is,

    A method to setup index

    var setupItemIndex = function(index) {
         return function(container) {
            container.find(".listItem").each(function(){
                        $(this).attr('data-index', index++);
            });
         };
      }(0);
    

    Then initiating the index setup for both containers,

    setupItemIndex($('#listContainer'));
    setupItemIndex($('#image_slot'));
    

    Then retrieving the index of the dropped item,

      var targetContainer = myImageSlot.children(".itemsContainer");
      var itemIndex = ui.draggable.attr('data-index');
    

    Then, checking this index whether exists already in the right container before appending it there.

    if(targetContainer.has('[data-index="' + itemIndex + '"]').length === 0) {
            myImageSlot.children(".itemsContainer").append(cloneTile);
    
            -----
    
    }
    

    Give a go :-)