jQuery sortable obtain 2 elements being swapped
Asked Answered
K

6

19

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.

Kathaleenkatharevusa answered 15/2, 2010 at 2:7 Comment(3)
@Dimitriy, there is no "second item" so it makes your question extremely unclear. If you are allowing a user to pick up and drop an item anywhere in the list, it is merely shifting the indexes to make room for it. Only if he moves it one place up or down, are only two items affected. But if he takes it from the top of the list, and drops it after the next three items, those first three items position are all affected by the move. No "switch" has occurred. PLease describe in more detail what you are needing to accomplish.Direction
How is the swapOnServer method?Mauricio
tried the solution, seems this line: var second = currentOrder[prevPagesOrder.indexOf(first)]; should be var second =prevPagesOrder[currentOrder.indexOf(first)];Og
M
5

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.

Morley answered 15/2, 2010 at 2:33 Comment(0)
V
7

You can use draggable and droppable instead of sortable to achieve swappable effect. In practise, this will look like this:

(function() {
    var droppableParent;

    $('ul .element').draggable({
        revert: 'invalid',
        revertDuration: 200,
        start: function () {
            droppableParent = $(this).parent();

            $(this).addClass('being-dragged');
        },
        stop: function () {
            $(this).removeClass('being-dragged');
        }
    });

    $('ul li').droppable({
        hoverClass: 'drop-hover',
        drop: function (event, ui) {
            var draggable = $(ui.draggable[0]),
                draggableOffset = draggable.offset(),
                container = $(event.target),
                containerOffset = container.offset();

            $('.element', event.target).appendTo(droppableParent).css({opacity: 0}).animate({opacity: 1}, 200);

            draggable.appendTo(container).css({left: draggableOffset.left - containerOffset.left, top: draggableOffset.top - containerOffset.top}).animate({left: 0, top: 0}, 200);
        }
    });
} ());

Demo, http://jsfiddle.net/FZ42C/1/.

Volar answered 2/9, 2013 at 20:39 Comment(0)
W
6

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.

Warrantor answered 15/2, 2010 at 2:13 Comment(6)
There's not much I can do with the whole list. I only need 2 items that has been swapped so I can post the change to server. I don't need to post to server the whole list swapping only 2 items.Kathaleenkatharevusa
I think Dmitriy is referring to jQuery UI Sortable, you're referring to Interface element's sortable.Slavism
Updated my answer to show you how to grab the item before the dropped item.Warrantor
ui.item.prev() is WRONG. It will return previous element. I need to obtain the second element being swapped. There is no anything that says it will be previous one.Kathaleenkatharevusa
there is no such thing as being "swapped" you are dropping something in the middle of a list. You can either send back the whole list in its new form, or send back the item that is before and/or after it in its new place. You aren't swapping anything.Warrantor
@petersendidit, thanks a lot for the help. I've just realised that i got it wrong. There is really no such thing as 'swapping' and I have to use the whole list. Updated the question to reflect that and voted your answer.Kathaleenkatharevusa
M
6

take a look at the "Swapable" jQuery plugin:

http://plugins.jquery.com/project/Swapable

It similar to "Sortable", but only two elements of the selected group are affected: dragged element and dropped one which are swapped. All other elements stay at their current positions. This plugin is built based on existing "Sortable" jQuery plugin and inherits all sortable options.

Millda answered 4/7, 2010 at 4:52 Comment(2)
it's the best! I would like to note to anyone trying to update their code from sortable to swappable that it is VERY IMPORTANT that you both define the items you want to drag explicitly AND that the cursor position is outside of the bounds of your dragged element, like so: $('#my-list').swappable({items: 'li', cursorAt: {top:-10}}); otherwise it won't workSubdebutante
But it sucks that you have to install another pluginStovall
M
5

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.

Morley answered 15/2, 2010 at 2:33 Comment(0)
K
0

You can use http://plugins.jquery.com/project/Swapable

but this is not too good plugin

Keystone answered 2/6, 2011 at 11:32 Comment(0)
E
-2

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>
Epididymis answered 9/8, 2022 at 13:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.