50

I have:

<ul id="sortableList">
     <li>item 1</li>
     <li>item 2</li>
     <li>item 3</li>
</ul>

I have wired into the update: function(event, ui) { } but am not sure how to get the original and new position of the element. If i move item 3 to be above item 1, I want the original position to be 2 (0 based index) and the new position of item 3 to be 0.

Doug
  • 1,850
  • 23
  • 50
Amir
  • 9,091
  • 5
  • 34
  • 46
  • 3
    The last answer from Richard with least number of upvotes is the best and cleanest solution, especially when you are using AngularJS or any other MVC frameworks where you dont want to read a custom attribute inside your controller! – Nishanth Nair Nov 01 '13 at 11:52

6 Answers6

102
$('#sortable').sortable({
    start: function(e, ui) {
        // creates a temporary attribute on the element with the old index
        $(this).attr('data-previndex', ui.item.index());
    },
    update: function(e, ui) {
        // gets the new and old index then removes the temporary attribute
        var newIndex = ui.item.index();
        var oldIndex = $(this).attr('data-previndex');
        $(this).removeAttr('data-previndex');
    }
});
Rush Frisby
  • 11,388
  • 19
  • 63
  • 83
18

When the update function is invoked the ui.item.sortable has not been updated, however the UI element has visually moved.
This allows you in the update function to get old position and new position.

   $('#sortable').sortable({    
        update: function(e, ui) {
            // ui.item.sortable is the model but it is not updated until after update
            var oldIndex = ui.item.sortable.index;

            // new Index because the ui.item is the node and the visual element has been reordered
            var newIndex = ui.item.index();
        }    
});
kameny
  • 2,372
  • 4
  • 30
  • 40
Richard Friedman
  • 932
  • 7
  • 11
10

You have several possibilities to check the old and the new position. I would put them into arrays.

$('#sortable').sortable({
    start: function(e, ui) {
        // puts the old positions into array before sorting
        var old_position = $(this).sortable('toArray');
    },
    update: function(event, ui) {
        // grabs the new positions now that we've finished sorting
        var new_position = $(this).sortable('toArray');
    }
});

And you can then easily extract what you need.

Frankie
  • 24,627
  • 10
  • 79
  • 121
6

This worked for me

$('#sortable').sortable({
start: function(e, ui) {
    // puts the old positions into array before sorting
    var old_position = ui.item.index();
},
update: function(event, ui) {
    // grabs the new positions now that we've finished sorting
    var new_position = ui.item.index();
}
});
nicmwenda
  • 139
  • 1
  • 3
  • This worked for me! It's worth noting that if you need to reference old_position within update() just declare it before the sortable. – nick Apr 24 '15 at 09:47
6

I was looking for an answer to the same issue. based on what Frankie contributed, I was able to get both the start and end "orders". I had an issue with variable scope using the var, so I just stored them as .data() instead of local vars:

$(this).data("old_position",$(this).sortable("toArray"))

and

$(this).data("new_position",$(this).sortable("toArray"))

now you can call it up like this (from the update/end functions):

console.log($(this).data("old_position"))
console.log($(this).data("new_position"))

Credit still goes to Frankie :)

jondavidjohn
  • 61,812
  • 21
  • 118
  • 158
jasonmcleod
  • 61
  • 1
  • 3
2

This works for me,

$('#app').sortable({
    handle: '.handle',

    start: function(evt, ui){
        $(ui.item).data('old-ndex' , ui.item.index());
    },

    update: function(evt, ui) {
        var old_index = $(ui.item).data('old-ndex');
        var new_index = ui.item.index();

        alert('old_index -'+old_index+' new index -'+new_index);

    }
});
lonestar
  • 377
  • 1
  • 7
  • 16