最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - JQuery sortable list with some elements frozen in order? - Stack Overflow

programmeradmin1浏览0评论

I am looking for a method to have a JQuery-like sortable list (link), but with some of the elements in fixed undraggable positions.

It's trivial to make some elements undraggable, but their positions don't remain fixed because the number of draggable elements above and below them can change.

To be more specific: I have a list of 10 items in rank order. I want the user to be able to change the rank for some of the items by dragging (a la sortable list), but not change the rank of other frozen elements. The standard JQuery sortable undraggable feature allows the rank of frozen items to be changed by changing the number of elements above or below the frozen ones.

I've tried do this manually by "swapping" list elements when dragging. I.e., when a list element is dragged over a non-frozen element, the position of the two elements is swapped. This gives the semantics I want, but the item being dragged visibly "jumps" between its new position and the current 'drag' position. (I want it to remain in its current drag position; only its position in the DOM should change. But when the DOM position changes, the drag offset coordinates must be recomputed. And I don't know how to do both the DOM position change and drag offset coordinate change atomically, preventing a redraw between the two. Currently, sometimes a redraw happens between the two, and the element visibly, albeit shortly, jumps.)

Edit Here's a jsfiddle showing my manual approach: link. Play with it for a while and you'll notice the flicker/jumping I mentioned.

I am looking for a method to have a JQuery-like sortable list (link), but with some of the elements in fixed undraggable positions.

It's trivial to make some elements undraggable, but their positions don't remain fixed because the number of draggable elements above and below them can change.

To be more specific: I have a list of 10 items in rank order. I want the user to be able to change the rank for some of the items by dragging (a la sortable list), but not change the rank of other frozen elements. The standard JQuery sortable undraggable feature allows the rank of frozen items to be changed by changing the number of elements above or below the frozen ones.

I've tried do this manually by "swapping" list elements when dragging. I.e., when a list element is dragged over a non-frozen element, the position of the two elements is swapped. This gives the semantics I want, but the item being dragged visibly "jumps" between its new position and the current 'drag' position. (I want it to remain in its current drag position; only its position in the DOM should change. But when the DOM position changes, the drag offset coordinates must be recomputed. And I don't know how to do both the DOM position change and drag offset coordinate change atomically, preventing a redraw between the two. Currently, sometimes a redraw happens between the two, and the element visibly, albeit shortly, jumps.)

Edit Here's a jsfiddle showing my manual approach: link. Play with it for a while and you'll notice the flicker/jumping I mentioned.

Share Improve this question edited Feb 23, 2012 at 16:00 graphicdivine 11.2k7 gold badges35 silver badges59 bronze badges asked Feb 16, 2012 at 20:19 David B.David B. 5,8805 gold badges36 silver badges53 bronze badges 4
  • Have you tried binding your behaviour to the beforeStop event? – graphicdivine Commented Feb 19, 2012 at 16:27
  • This sounds pretty interesting, and I gather you already have some almost-working code? Please consider creating a jsfiddle with what you've got! – Linus Thiel Commented Feb 20, 2012 at 11:32
  • 2 @LinusGThiel, I added a link to a jsfiddle showing my manual attempt. – David B. Commented Feb 21, 2012 at 8:20
  • @graphicdivine, can you expand on that? What behavior should I add on beforeStop? – David B. Commented Feb 21, 2012 at 8:23
Add a comment  | 

4 Answers 4

Reset to default 14 +50

I've looked at your fiddle, had another think, and here's one way to do it using sortable: on start store the fixed index positions in the data object of each fixed item, and then on any change, move the fixed items back into place.

$(function() {   
    $('#rankings').sortable({
        axis: 'y',
        items: '.sortable',
        start: function () {
            $(this).find("li:not(.sortable)").each(function () {
                $(this).data("fixedIndex", $(this).index());
            });
        },        
        change: function () {
            $(this).find("li:not(.sortable)").each(function () {
                $(this).detach().insertAfter($("#rankings li:eq(" + ($(this).data("fixedIndex")-1) + ")"));
            });
        }
    });
});

Using a list such as:

<ol id="rankings">
    <li class="sortable">Dog</li>
    <li class="">Cat</li>
    <li class="sortable">Parrot</li>
    <li class="sortable">Gerbil</li>
    <li class="sortable">Snake</li>
    <li class="">Goldfish</li>
</ol>

Seems to work.

I think I might have cracked it - http://jsfiddle.net/q5c4Y/3/. Quite a challenge though. A few things helped along the way

  • Using more structured markup
  • Using droppable's over event to swap list items, but not the drop event (using dragstop instead)
  • Setting some positioning on inner items in order to keep them in the right position after changing their parent element

Although, reading @graphicdivine's answer above, it looks like what you really needed all along is jquery ui sortable

1) If the items you do not want changeable are all at the top and/or bottom of the list, you can create those items outside of the list, thereby allowing only of the sorting of OTHER items and preserving the rankings of the immutable ones.

2) Can you use the "stop" event to check that the rankings of the ones you want has been preserved? ie, check that there are still only 3 items above the 4th ranking item, and if not, move the new "4th" below the one that has an immutable rank of 4th? Basically, force a re-shifting of items after the item has been dragged into an illegal spot?

Update 2023:

//html
<div id="example6" class="list-group col">
    <div class="list-group-item">Item 1</div>
    <div class="list-group-item" style="">Item 2</div>
    <div class="list-group-item" style="">Item 3</div>
    <div class="list-group-item bg-danger filtered" style="">Filtered</div>
    <div class="list-group-item" style="">Item 4</div>                  
    <div class="list-group-item" draggable="false" style="">Item 5</div></div>
//js
new Sortable(example6, {
    filter: '.filtered', // 'filtered' class is not draggable
    animation: 150
});
发布评论

评论列表(0)

  1. 暂无评论