jQuery sortable obtain 2 elements being swapped

Viewed 14027

I cannot find out how to obtain destination element with jQuery UI sortable.

    $("#pages").sortable({
        opacity: 0.6,
        update: function(event, ui) {
            var first = ui.item; // First element to swap
            var second = ???? // Second element to swap
            swapOnServer(first, second);
        }
    });

All the options I've tried point to the element being dragged, but not the one it is swapped with: ui.item[0], event.srcElement, event.toElement.

Additionally, this points to the LIST (OL) element.

Saying second I mean following:

Original order is:

| 0 | 1 | 2 | 3 |

We drag element 1 and drop it in position 3. Which will end up with:

| 0 | 3 | 2 | 1 |

So the first element is 1 and the second is 3 (WRONG! See below).

UPDATE: I have realised that I got it wrong. The new order in this case will be.

| 0 | 2 | 3 | 1 |

As a result my question does not really makes sense. Thanks everybody for the help. I'll mark vote and mark an answer.

So the question is how to obtain the second element here?


THE CURRENT WORKAROUND (as there is no term as swapping in sortable) is below. It uses temporary array with orders.

    var prevPagesOrder = [];
    $("#pages").sortable({
        start: function(event, ui) {
            prevPagesOrder = $(this).sortable('toArray');
        },
        update: function(event, ui) {
            var currentOrder = $(this).sortable('toArray');
            var first = ui.item[0].id;
            var second = currentOrder[prevPagesOrder.indexOf(first)];
            swapOnServer(first, second);
        }
    });

Thanks,
Dmitriy.

6 Answers

Try using the serialize function which gives you a hash of the list of items in order.

If you just need the item that the new item go dropped before you can do this:

$("#pages").sortable({
    opacity: 0.6,
    update: function(event, ui) {
        var first = ui.item; // First element to swap
        var second = ui.item.prev();
        swapOnServer(first, second);
    }
});

second will be null if its at the start of the list.

There's not really a "second" item per se. You have an item, and you are simply placing it in another location. The items around it adjust their positions accordingly. If you want to get an array of all the items, you can use the toArray method.

After reviewing the code I have made some behavior improvements:

<!doctype html>

<html><head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title></title>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">
  <meta name="viewport" content="width=device-width, initial-scale=1">

<style id="compiled-css" type="text/css">

ul,
li{ margin: 0; padding: 0; }

ul { float:left; height: 120px; background: #CCC; overflow:auto; }

li { list-style: none; float: left; width: 100px; height: 100px; background: yellow; margin: 10px;  position: relative; border: "1px solid yellow"}
li.drop-hover .element { opacity: .5; }

.element { position: absolute; width: 100px; height: 100px; background: #00f; color: #fff; text-align: center; line-height: 100px; z-index: 5; }
.element.being-dragged { background-color: #f00; z-index: 9999; }

</style>

<script src="//...jquery-3.6.0.min.js"></script>
<script src="//...jquery-ui.min.js"></script>

</head>

<body style="cursor: auto;">

<ul>
    <li class="ui-droppable">
        <div class="element a ui-draggable">a</div>
    </li>
    <li class="ui-droppable">
        <div class="element b ui-draggable">b</div>
    </li>
    <li class="ui-droppable">
        <div class="element c ui-draggable">c</div>
    </li>
</ul>

<script type="text/javascript">

(function() {
    var droppableParent;
    var superDrop;
    
    $('ul .element').draggable({
        revert: true,
        revertDuration: 200,
        
        start: function (event, ui) {
        
            droppableParent = $(this).parent();
            
            ui.helper.css({zIndex: 9999, opacity: 0.5, border: "1px solid black"})
        },
        stop: function (event, ui) {
        
            ui.helper.css({zIndex: 1, opacity: 1, border: "1px solid blue"})
        }
    });
    
    $('ul li').droppable({

        over: function( event, ui ) {
            
            var draggable_clase = ui.draggable.attr("class");
            var clase_actual = $(event.target).find(" > .element").attr("class")
            var droppable = $(this).find(" > .element");
            superDrop = $(this).find(" > .element")
            
            if(draggable_clase != clase_actual)
                droppable.css({border: "3px solid red", backgroundColor : "yellow"});
            
            console.log(draggable_clase + "\n" + clase_actual)
        },
        out: function( event, ui ) {
        
            var draggable_clase = ui.draggable.attr("class");
            var clase_actual = $(event.target).find(" > .element").attr("class")
            var droppable = $(this).find(" > .element");
            
            if(draggable_clase != clase_actual)
                droppable.css({border: "0px solid red", backgroundColor : "blue"});
                
            var droppable = $(this).find(" > .element");
            //droppable.css({border: "0px", backgroundColor : "#00f"});
        },
        drop: function (event, ui) {
        
            var draggable = $(ui.draggable[0]),
                draggableOffset = draggable.offset(),
                container = $(event.target),
                containerOffset = container.offset();
            
            $(this).find(" > .element").appendTo(droppableParent);
            //$(this).find(" > .element").css({zIndex: 1, opacity: 0.5, border: "1px solid black"})
            //$(this).find(" > .element").css({opacity: 0.35}).animate({opacity: 1}, 200);
            
            superDrop.css({border: "0px solid orange", backgroundColor : "blue"});
            
            draggable.appendTo(container).css({
                left: draggableOffset.left - containerOffset.left, 
                top: draggableOffset.top - containerOffset.top})
            .animate({left: 0, top: 0}, 200);
        }
    });
} ());

</script>
Related