133

I want to use the jQuery UI sortable function to allow users to set an order and then on change, write it to the database and update it. Can someone write an example on how this would be done?

The Codesee
  • 3,714
  • 5
  • 38
  • 78
Harry
  • 3,301
  • 7
  • 27
  • 33

6 Answers6

243

The jQuery UI sortable feature includes a serialize method to do this. It's quite simple, really. Here's a quick example that sends the data to the specified URL as soon as an element has changes position.

$('#element').sortable({
    axis: 'y',
    update: function (event, ui) {
        var data = $(this).sortable('serialize');

        // POST to server using $.post or $.ajax
        $.ajax({
            data: data,
            type: 'POST',
            url: '/your/url/here'
        });
    }
});

What this does is that it creates an array of the elements using the elements id. So, I usually do something like this:

<ul id="sortable">
   <li id="item-1"></li>
   <li id="item-2"></li>
   ...
</ul>

When you use the serialize option, it will create a POST query string like this: item[]=1&item[]=2 etc. So if you make use - for example - your database IDs in the id attribute, you can then simply iterate through the POSTed array and update the elements' positions accordingly.

For example, in PHP:

$i = 0;

foreach ($_POST['item'] as $value) {
    // Execute statement:
    // UPDATE [Table] SET [Position] = $i WHERE [EntityId] = $value
    $i++;
}

Example on jsFiddle.

samuel
  • 326
  • 2
  • 9
Knelis
  • 6,782
  • 2
  • 34
  • 54
  • 7
    To generate IDs automatically you can use `$("#element").children().uniqueId().end().sortable({...` – Taylan Apr 28 '14 at 08:59
  • 13
    documentation says for using serialize option you should define id as **name_number** format. – parisssss Jun 15 '14 at 19:12
  • 5
    You can also use these other character per the documentation: _You can use an underscore, equal sign or hyphen to separate the set and number. For example "foo=1", "foo-1", and "foo_1" all serialize to "foo[]=1"._ – lhoess Oct 29 '14 at 20:44
  • 2
    I can't seem to get this to work if I'm passing multiple data variables. – PBwebD Mar 13 '15 at 15:37
  • @Kalpesh Popat 's answer is much more agile. See 3 answers below this one. – Zbigniew Ledwoń Jan 21 '16 at 14:13
  • Perfect example and working example. Thanks for the help – Vivek Apr 04 '16 at 07:05
  • @Knelis Hi..question..what would be `[Position]`? – Maduro Jan 20 '17 at 16:55
  • 1
    this may help you http://codingbin.com/reorder-with-php-mysql-and-jquery-sortable/ – Manoj Dhiman Mar 02 '17 at 23:51
  • Important note from the docs: "If serialize returns an empty string, make sure the id attributes include an underscore. They must be in the form: "set_number" For example, a 3 element list with id attributes "foo_1", "foo_5", "foo_2" will serialize to "foo[]=1&foo[]=5&foo[]=2". You can use an underscore, equal sign or hyphen to separate the set and number." – stef Jun 10 '17 at 06:11
  • What is $('#element')? I could not see id called element? – Damith Ruwan Jun 20 '17 at 05:41
  • should $('#element').sortable({ not be $('#sortable').sortable({ ?? – Craig Edmonds Aug 19 '17 at 08:19
  • The id depends on you. If you use `
      `, you'll have to use `$("#sortable")`. If you use `
        `, you'll use `$("#element")`, etc... The examples in the answer are not connected nor related to each other
    – Shinra tensei Aug 25 '17 at 12:02
13

Thought this might help as well. A) it was designed to keep payload to its minimum while sending back to server, after each sort. (instead of sending all elements each time or iterating through many elements that server might chuck out) B) I needed to send back custom id without compromising the id / name of the element. This code will get the list from asp.net server and then upon sorting only 2 values will be sent back: The db id of sorted element and db id of the element next to which it was dropped. Based on those 2 values, server can easily identify the new postion.

<div id="planlist" style="width:1000px">
    <ul style="width:1000px">
       <li plid="listId1"><a href="#pl-1">List 1</a></li>
       <li plid="listId2"><a href="#pl-2">List 1</a></li>
       <li plid="listId3"><a href="#pl-3">List 1</a></li>
       <li plid="listId4"><a href="#pl-4">List 1</a></li>
    </ul>
    <div id="pl-1"></div>
    <div id="pl-2"></div>
    <div id="pl-3"></div>
    <div id="pl-4"></div>
</div>
<script type="text/javascript" language="javascript">
    $(function () {
        var tabs = $("#planlist").tabs();
        tabs.find(".ui-tabs-nav").sortable({
            axis: "x",
            stop: function () {
                tabs.tabs("refresh");
            },
            update: function (event, ui) {
                //db id of the item sorted
                alert(ui.item.attr('plid'));
                //db id of the item next to which the dragged item was dropped
                alert(ui.item.prev().attr('plid'));

                //make ajax call
            }
        });
    });
</script>
Kalpesh Popat
  • 1,416
  • 14
  • 12
  • 4
    ASP tags may be confusing to those unfamiliar with them and this is purely a jQuery/HTML issue. – ggdx Jun 16 '15 at 12:54
  • 1
    Two years later! Been busy? – ggdx Oct 13 '17 at 20:10
  • What happens if the moved item gets dropped as the first item of the list? – Edson Horacio Junior Nov 17 '17 at 16:50
  • 1
    if any item gets dropped, then the "next to" id = 0, action=del and plid=id of the item being acted upon, else action=sort and there are 2 param, item being sorted and next to which it is dropped. thats the minimum information that the server can use for performing rest of the operations. it is tried and test pattern. i even have add and insert using same pattern - just the play of action and the other 2 params. – Kalpesh Popat Nov 21 '17 at 09:54
9

You're in luck, I use the exact thing in my CMS

When you want to store the order, just call the JavaScript method saveOrder(). It will make an AJAX POST request to saveorder.php, but of course you could always post it as a regular form.

<script type="text/javascript">
function saveOrder() {
    var articleorder="";
    $("#sortable li").each(function(i) {
        if (articleorder=='')
            articleorder = $(this).attr('data-article-id');
        else
            articleorder += "," + $(this).attr('data-article-id');
    });
            //articleorder now contains a comma separated list of the ID's of the articles in the correct order.
    $.post('/saveorder.php', { order: articleorder })
        .success(function(data) {
            alert('saved');
        })
        .error(function(data) { 
            alert('Error: ' + data); 
        }); 
}
</script>
<ul id="sortable">
<?php
//my way to get all the articles, but you should of course use your own method.
$articles = Page::Articles();
foreach($articles as $article) {
    ?>
    <li data-article-id='<?=$article->Id()?>'><?=$article->Title()?></li>
    <?
}               
?>   
</ul>
   <input type='button' value='Save order' onclick='saveOrder();'/>

In saveorder.php; Keep in mind I removed all verification and checking.

<?php
$orderlist = explode(',', $_POST['order']);
foreach ($orderlist as $k=>$order) {
  echo 'Id for position ' . $k . ' = ' . $order . '<br>';
}     
?>
Quill
  • 2,729
  • 1
  • 33
  • 44
Hugo Delsing
  • 13,803
  • 5
  • 45
  • 72
7

This is my example.

https://github.com/luisnicg/jQuery-Sortable-and-PHP

You need to catch the order in the update event

    $( "#sortable" ).sortable({
    placeholder: "ui-state-highlight",
    update: function( event, ui ) {
        var sorted = $( "#sortable" ).sortable( "serialize", { key: "sort" } );
        $.post( "form/order.php",{ 'choices[]': sorted});
    }
});
luisnicg
  • 304
  • 2
  • 3
0

I can change the rows by following the accepted answer and associated example on jsFiddle. But due to some unknown reasons, I couldn't get the ids after "stop or change" actions. But the example posted in the JQuery UI page works fine for me. You can check that link here.

Web_Developer
  • 1,251
  • 2
  • 18
  • 34
0

Try with this solution: http://phppot.com/php/sorting-mysql-row-order-using-jquery/ where new order is saved in some HMTL element. Then you submit the form with this data to some PHP script, and iterate trough it with for loop.

Note: I had to add another db field of type INT(11) which is updated(timestamp'ed) on each iteration - it serves for script to know which row is recenty updated, or else you end up with scrambled results.

TomoMiha
  • 1,218
  • 1
  • 14
  • 12