31

In the code below the update function gets called twice when an item is moved from list sortable1 to sortable2. Though I need to call that function only once:

$("#sortable1 tbody, #sortable2 tbody").sortable({
    connectWith: '.connectedSortable tbody',
    helper: fixHelper,
    handle : '.handle',
    update : function () {
        var order = $('#sortable1 tbody').sortable('serialize');
    }    
}).disableSelection();
MichaelS
  • 7,023
  • 10
  • 51
  • 75
Abhishek Jain
  • 971
  • 3
  • 13
  • 18

8 Answers8

63

Answer from: http://forum.jquery.com/topic/sortables-update-callback-and-connectwith

update: function(e,ui) {
    if (this === ui.item.parent()[0]) {
        //your code here
    }
}
Stefan
  • 4,166
  • 3
  • 33
  • 47
  • 9
    It worth noting `this` is the interesting value here. `update` is fired twice namely by the list where the element is dragged out and the list the element was dragged into. `ui.item.parent()` refers to the parent of the dragged element. If you wonder why this works :) – nuala Feb 06 '13 at 16:50
13

Stefan's answer was good, but it doesn't mention one more piece of the puzzle, so here it is - in case someone (like me) doesn't get it right away. This should make it possible for you to handle it all in the update() function and to not have to mess with receive() (which will get triggered only when inter-container movements happen):

update: function(e,ui) {
    if (this === ui.item.parent()[0]) {
        if (ui.sender !== null) {
          // the movement was from one container to another - do something to process it
          // ui.sender will be the reference to original container
        } else {
          // the move was performed within the same container - do your "same container" stuff
        }
    }
}
snumpy
  • 2,808
  • 6
  • 24
  • 39
userfuser
  • 1,350
  • 1
  • 18
  • 32
6

Try this:

update: function(e,ui) {
    if (!ui.sender) {
        //your code here
    }
}
Code Slinger
  • 1,100
  • 1
  • 11
  • 16
5

You should be using the receive event (http://jqueryui.com/demos/sortable/#event-receive).

Check out the resolution at the very bottom at http://bugs.jqueryui.com/ticket/3178.

Brad Gessler
  • 2,744
  • 4
  • 23
  • 22
  • 1
    Well then how do you handle sorting within the same list as well as a connected list? How do you know which one to honor? – Jason Jul 22 '11 at 20:17
  • 1
    @Jason: found the answer at http://forum.jquery.com/topic/sortables-update-callback-and-connectwith – Stefan Sep 07 '11 at 20:33
3

In order to call the update function only once, it is best to use the stop event, which indicates that the drag & drop has been finished. It will fire only once regardless if the drag&drop was within the same or connected lists.

$('.selector').sortable({
  stop: function(event, ui ) {
    ...
  }
})
Paweł Gościcki
  • 9,066
  • 5
  • 70
  • 81
Pablo Vallejo
  • 201
  • 4
  • 5
2

How about using remove, receive and update to capture all changes and send them to the server as an array?

Demo: http://jsfiddle.net/r2d3/p3J8z/

$(function(){

    /* Here we will store all data */
    var myArguments = {};   

    function assembleData(object,arguments)
    {       
        var data = $(object).sortable('toArray'); // Get array data 
        var step_id = $(object).attr("id"); // Get step_id and we will use it as property name
        var arrayLength = data.length; // no need to explain

        /* Create step_id property if it does not exist */
        if(!arguments.hasOwnProperty(step_id)) 
        { 
            arguments[step_id] = new Array();
        }   

        /* Loop through all items */
        for (var i = 0; i < arrayLength; i++) 
        {
            var image_id = data[i]; 
            /* push all image_id onto property step_id (which is an array) */
            arguments[step_id].push(image_id);          
        }
        return arguments;
    }   

    /* Sort images */
    $('.step').sortable({
        connectWith: '.step',
        items : ':not(.title)',
        /* That's fired first */    
        start : function( event, ui ) {
            myArguments = {}; /* Reset the array*/  
        },      
        /* That's fired second */
        remove : function( event, ui ) {
            /* Get array of items in the list where we removed the item */          
            myArguments = assembleData(this,myArguments);
        },      
        /* That's fired thrird */       
        receive : function( event, ui ) {
            /* Get array of items where we added a new item */  
            myArguments = assembleData(this,myArguments);       
        },
        update: function(e,ui) {
            if (this === ui.item.parent()[0]) {
                 /* In case the change occures in the same container */ 
                 if (ui.sender == null) {
                    myArguments = assembleData(this,myArguments);       
                } 
            }
        },      
        /* That's fired last */         
        stop : function( event, ui ) {                  
            /* Send JSON to the server */
            $("#result").html("Send JSON to the server:<pre>"+JSON.stringify(myArguments)+"</pre>");        
        },  
    });
});

Here is the full explanation of the solution: http://r2d2.cc/2014/07/22/jquery-sortable-connectwith-how-to-save-all-changes-to-the-database/

Artur Kedzior
  • 3,994
  • 1
  • 36
  • 58
1

I just ran into this. It's a bug in jQuery UI, see http://bugs.jqueryui.com/ticket/4872#comment:2

I commented to see if I can wake anyone up as to when there will be a fix. The joys of community driven development :P

Jon Scalet
  • 197
  • 1
  • 2
  • 12
0
update: function(e, ui) {
    var draggedOut = this !== ui.item.parent()[0] && !$.contains(this, ui.item.parent()[0]);
    var draggedIn = ui.sender !== null;
    var sameList = !draggedOut && !draggedIn;

    if (sameList || draggedIn) {
        // Do stuff
    }
}
Dunc
  • 18,404
  • 6
  • 86
  • 103