JQuery sortable lists and fixed/locked items

Check this out: Forcing an item to remain in place in a jQuery UI Sortable list

Also, I've implemented the above solution with multiple fixed elements here: http://jsfiddle.net/enBnH/12/ (obsolete, see below) It's rather self-explanatory, i think.

EDIT:

I've automated the process for generating the lockto values as well as adding ID's to those lis with the class "fixed" (note that i have to add an ID so we can reference it)

See the COMPLETE solution HERE: http://jsfiddle.net/enBnH/44/

EDIT

Okay, after a gazillion errors with the above, i just rewrote the dang thing myself: http://jsfiddle.net/thomas4g/GPMZZ/15/

NOTE: The above does work, but @DarthJDG's answer seems a lot nicer to me. I'm leaving mine up on the offchance someone might prefer how mine behaves (i've learned not to delete stuff just beceause there's a better version :P )


I extended the jQuery.Ui.sortable:

Overview

jQuery.Ui.sortable widget extension with fixed feature. This feature allows user to fix elements in the list.
With the .fixedsortable() constructor you construct a .sortable() class which extended with the features. You can use the original methods and the extended as well.

Code

https://gist.github.com/3758329#file_fixedsortable.js > fixedsortable.js

Example

http://jsfiddle.net/omnosis/jQkdb/

Usage

General:

To use, add the fixed property to the sortable list optios:

$("#list").fixedsortable({
   fixed: (value)
})

the value can be:

  • integer example: 3
  • array of integers example : [1,2,5]
  • a html element or a list of html elements
  • a css selector
  • jquery object

HTML:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> //the jquery 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script> //the original jquery-ui   
<script type="text/javascript" src="https://raw.github.com/gist/3758329/91749ff63cbc5056264389588a8ab64238484d74/fixedsortable.js"></script> //the extended sortable
...
<ul id="sortable1">
    <li>oranges</li>
    <li class="static">apples</li>
    <li>bananas</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li class="static">pears</li>
    <li>mango</li>
</ul>

<ul id="sortable2">
    <li>bananas</li>
    <li foo="asd">oranges</li>
    <li foo="dsa">apples</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li>pears</li>
    <li>mango</li>
</ul>

<ul id="sortable3">
    <li>bananas</li>
    <li>oranges</li>
    <li>apples</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li>pears</li>
    <li>mango</li>
</ul>

Javascript

$(function() {
    $("#sortable1").fixedsortable({
        fixed: "> .static"
    });

    $("#sortable2").fixedsortable({
        fixed: $("li[foo]").css("background","red")
    });

    $("#sortable3").fixedsortable({
        fixed: 2
    })
});

Notes:

If you insist to use the .sortable instead of .fixedsortable you can use this https://gist.github.com/3758329#file_sortable.js instead of the jquery.ui library. This is a complete replacement of the jQuery.ui, but i don't recommend to use this because of later updates.

i have been working on this more than 12 hours :( i am insane..


Using the items parameter you can achieve what you want like this:

$("#mytable tbody").sortable({items: 'tr.sortable'});

Only rows with a .sortable CSS class can be sorted now.

If you want to lock only the 1st row you can do this:

$("#mytable tbody").sortable({items: 'tr:not(:first)'});

The possibilities are endless...


Here's a hopefully bug-free version, updating as you drag. It's generating the current desired positions of the items when sorting starts, which means you should be able to change the classes whenever you need, refresh the widget's list items and you're good to go.

It also uses the sortable's built-in items property to prevent dragging the fixed items and to sort out any sorting problems at the top and the bottom of the list.

I tried to move the fixed items around, but that resulted in horribly buggy behaviour, especially when there are multiple fixed items in groups. The final solution detaches all fixed items from the list, adds a helper element to the front, then re-inserts the fixed elements to their desired position, which seems to fix all bugs.

Try the demo here: http://jsfiddle.net/PQrqS/1/

HTML:

<ul id="sortable">
    <li>oranges</li>
    <li class="static">apples</li>
    <li>bananas</li>
    <li>pineapples</li>
    <li>grapes</li>
    <li class="static">pears</li>
    <li>mango</li>
</ul>

CSS:

.static { color:red; }

li { background-color:whitesmoke; border:1px solid silver; width:100px; padding:2px; margin:2px; }

Javascript:

$('#sortable').sortable({
    items: ':not(.static)',
    start: function(){
        $('.static', this).each(function(){
            var $this = $(this);
            $this.data('pos', $this.index());
        });
    },
    change: function(){
        $sortable = $(this);
        $statics = $('.static', this).detach();
        $helper = $('<li></li>').prependTo(this);
        $statics.each(function(){
            var $this = $(this);
            var target = $this.data('pos');

            $this.insertAfter($('li', $sortable).eq(target));
        });
        $helper.remove();
    }
});