views:

214

answers:

2

I've set up a jQuery sortable list but I need to be able to keep some items in the sortable 'fixed' in place and for the other items to sort around them. I thought that there would be built in methods to achieve this, alas this is not the case.

I'm able to set up the list and not include the items in question:

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

<script type="text/javascript">
    $('#fruit').sortable({items: "li:not('.fixed')"})
</script>

This stops me from drag/dropping these items but they still move if the items around them are sorted. There may be a way to do this using the many callbacks that this method has but I've been unable to work this out.

Maybe this method would be a good addition to the UI Sortable options?

+1  A: 

This is non trivial I guess. For your example it's still feasible with a little work (a generic solution would be a bit harder)

Check http://jsbin.com/etubi/2 for a demo (http://jsbin.com/etubi/2/edit for the code)

$("#sortable").sortable({
    cancel: "li.fixed", //exclude fixed ones
    stop:function(event, ui) {
        //nothing to do for #f0 as you can't sort anything above it
        var f5 = $("#f5");
        var indf5 = $("#sortable li").index(f5);
        //if f5 not in right position -> swap position
        if(indf5 !== 5) {
            if(indf5 > 5) {
                f5.prev().insertAfter(f5); //move it up by one position
            } else {
                f5.next().insertBefore(f5); //move it down by one position
            }
        }
    }
});
jitter
Thanks for you answer.This solution will work for me, however there is still the problem of the items appearing to move during the sort (which is fixed when the sort has finished).A *perfect* solution would mean that the item stays fixed (visually) while the sort is taking place. With the number of event handlers available I think this may be possible.
calumbrodie
+1  A: 

I managed to do this by modifying jitters code a bit, and attach it to the "change" event rather than the "stop". I did it by looking how the index changes when dragging an item around and set up some conditionals. It also works with multiple fixed elements. The "lockto" variable defines the positon of the fixed element, and the fixed element should be in this position initially. You could probably rewrite this and wrap it in a function so you don't need to manually set the "lockto" variable for all fixed elements.

$("#sortable").sortable({
    "cancel":"li.static",
    "change":function(event,ui) {
        var lockto = 6;
        var thisindex = $(ui.helper).index(fixed);         
        var fixed = $("#static-"+lockto);           
        var index = $("#sortable li").index(fixed);
        var targetindex = lockto+1;
        if(index !== targetindex) {         
            if(index > targetindex ) {
                fixed.prev().insertAfter(fixed); //move it up by one position
            } else if(index==(targetindex-1) && thisindex>targetindex) {
                //don't move it at all
            } else {
                fixed.next().insertBefore(fixed); //move it down by one position
            }
        } else if(index==targetindex && thisindex>targetindex) {
            fixed.prev().insertAfter(fixed); //move it up by one position
        }       
    }
});
tester testers
Thanks for your response - I will try to test this out when I get a spare 10 minutes ;-)
calumbrodie