JQuery listes sortables et articles fixes / verrouillés

est-il possible de verrouiller des éléments de liste dans la liste sortable JQuery d'une manière que ces éléments resteront à cet endroit particulier dans la liste.

par exemple,

considérez cette pseudo liste avec des articles verrouillés...

item A
item B(locked)
item C(locked)
item D
item E
item F
item G(locked)

donc, je voudrais que les éléments B,C et G soient fixés d'une manière que si l'utilisateur glisser et déposer l'élément D au début de la liste, L'élément A "saute" sur les éléments B et c fixes/verrouillés avec la suivante résultat...

item D
item B(locked)
item C(locked)
item A
item E
item F
item G(locked)

j'ai cherché quelque chose comme ça sans succès. Est-il possible..?

29
demandé sur T J 2010-11-29 00:39:40

8 réponses

j'ai étendu la jQuery.Ui.sortable :

vue d'ensemble

jQuery.Ui.sortable extension du widget avec la fonctionnalité fixed . Cette fonctionnalité permet à l'utilisateur de fixer des éléments dans la liste.

Avec le constructeur .fixedsortable() vous construisez une classe .sortable() qui s'est étendue avec les caractéristiques. Vous pouvez utiliser les méthodes original et le étendu comme bien.

Code

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

exemple

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

Utilisation

général:

à utiliser, ajouter la propriété fixed à la liste sortable optios:

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

la valeur peut être:

  • entier exemple: 3
  • array de nombres entiers exemple: [1,2,5]
  • a élément html ou une liste d'éléments html
  • un sélecteur css
  • jquery objet

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:

si vous insistez pour utiliser le .sortable au lieu de .fixedsortable vous pouvez utiliser ce https://gist.github.com/3758329#file_sortable.js au lieu du jquery.bibliothèque d'interface utilisateur. Il s'agit d'un remplacement complet du jQuery.ui , mais je ne recommande pas de l'utiliser en raison de mises à jour ultérieures.

j'ai travaillé plus de 12 heures :( je suis fou..

25
répondu Gergely Fehérvári 2012-09-20 21:07:42

Voici une version avec un peu de chance sans bug, mise à jour au fur et à mesure que vous faites glisser. Il génère les positions désirées actuelles des éléments lors du tri commence, ce qui signifie que vous devriez être en mesure de changer les classes chaque fois que vous avez besoin, rafraîchir la liste des éléments du widget et vous êtes bon pour aller.

il utilise également la propriété intégrée items de sortable pour empêcher le déplacement des articles fixes et pour régler tout problème de tri en haut et en bas de la liste.

j'ai essayé de déplacer les éléments fixes autour, mais cela a entraîné un comportement horriblement buggy, surtout quand il ya plusieurs éléments fixes dans les groupes. La solution finale détache tous les éléments fixes de la liste, ajoute un élément helper à l'avant, puis ré-insère les éléments fixes à leur position désirée, ce qui semble corriger tous les bugs.

essayez la démo ici: 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();
    }
});
55
répondu DarthJDG 2011-05-25 22:40:27

Check this out: Forçant un élément de rester en place dans un jQuery UI liste Triable

aussi, j'ai mis en œuvre la solution ci-dessus avec plusieurs éléments fixes ici: http://jsfiddle.net/enBnH/12 / (obsolète, voir ci-dessous)) C'est plutôt l'auto-explicatif, je pense.

EDIT:

j'ai aussi automatisé le processus pour générer les valeurs de lockto comme ajouter des ID à ces li s avec la classe "fixe" (notez que je dois ajouter un ID pour que nous puissions le référencer)

voir la solution complète ici: http://jsfiddle.net/enBnH/44 /

EDIT

OK, après un million d'erreurs avec ce qui précède, j'ai juste réécrit la chose dang moi-même: http://jsfiddle.net/thomas4g/GPMZZ/15 /

NOTE: ce qui précède ne fonctionne pas, mais la réponse de @DarthJDG me semble bien plus gentille. Je laisse les miennes sur le offchance quelqu'un pourrait préférer comment les miennes se comportent (j'ai appris à ne pas supprimer des trucs juste parce qu'il y a une meilleure version :P)

8
répondu Thomas Shields 2017-05-23 11:54:54

en utilisant le paramètre items vous pouvez obtenir ce que vous voulez comme ceci:

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

seules les lignes avec une classe CSS .sortable peuvent être triées maintenant.

si vous ne voulez verrouiller que la première rangée, vous pouvez le faire:

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

Les possibilités sont infinies...

3
répondu Leniel Maccaferri 2014-01-23 21:48:15

basé sur le code @DarthJDG. Cependant, il ne récupérait pas toutes les pièces d'identité et le tri ne fonctionnait pas avec la table. J'ai donc réussi à mettre à jour sa solution qui fonctionne à la fois avec list et tables et garde l'id dans le tableau.

Javascript:

var fixed = '.static'; //class which will be locked
var items = 'li'; //tags that will be sorted

$('ul').sortable({
  cancel: fixed,
  items: items,
  start: function () {
    $(fixed, this).each(function () {
      var $this = $(this);
      $this.data('pos', $this.index());
    });
  },
  change: function () {
    var $sortable = $(this);
    var $statics = $(fixed, this).detach();
    var tagName = $statics.prop('tagName');
    var $helper = $('<'+tagName+'/>').prependTo(this);
    $statics.each(function () {
      var $this = $(this);
      var target = $this.data('pos');
      $this.insertAfter($(items, $sortable).eq(target));
    });
    $helper.remove();
  }
});

Démo: http://plnkr.co/edit/hMeIiRFT97e9FGk7hmbs

3
répondu sarunast 2014-07-16 12:01:33

articles durables et fixes connectés

j'ai rencontré le problème quand nous avons plusieurs sortables connectés. Le code suggéré par @sarunast et @DarthJDG a un comportement erroné lors du déplacement d'éléments d'une liste à une autre. Par conséquent, je l'ai modifié un peu, et maintenant vous pouvez faire glisser des articles de différentes listes avec des positions de sauvegarde dans les deux.

javascript:

let connected = '.soratble';
let fixed = '.static';
let newParentContainer;

//wrap the code suggested by @sarunast and @DarthJDG into the function
//code was modified a little
function sortingAroundFixedPositions(container) {
  let sortable = $(container);
  let statics = $(fixed, container).detach();
  let tagName = statics.prop('tagName');
  let helper = $('<' + tagName + '/>').prependTo(container);
  statics.each(function() {
    let target = this.dataset.pos;
    let targetPosition = $(tagName, sortable).eq(target);
    if (targetPosition.length === 0) {
      targetPosition = $(tagName, sortable).eq(target - 1)
    }
    $(this).insertAfter(targetPosition);
  });
  helper.remove();
}

$('ul').sortable({
  connectWith: connected,
  cancel: fixed,
  start: function() {
    $(fixed, connected).each(function() {
      this.dataset.pos = $(this).index();
    });
  },
  change: function(e, ui) {
    sortingAroundFixedPositions(this);
    if (ui.sender) {
      newParentContainer = this;
    }
    if (newParentContainer) {
      sortingAroundFixedPositions(newParentContainer);
    }
  },
  update: function(e, ui) {
    newParentContainer = undefined;
  }
});

démo: http://plnkr.co/edit/blmv4ZjaWJFcjvO2zQH0

1
répondu Ilya Shashilov 2018-03-13 18:17:28

oh non! gist lien est rompu. voici le code dump de https://gist.github.com/peterh-capella/4234752

code Accédé le 6 janvier 2016

//this code is created to fix this problem: /q/jquery-sortable-lists-and-fixed-locked-items-25398/"ui.fixedsortable", $.ui.sortable, {

    options: $.extend({},$.ui.sortable.prototype.options,{fixed:[]}),

    _create: function() {
      var o = this.options;
      this.containerCache = {};
      this.element.addClass("ui-sortable");

      //Get the items
      $.ui.sortable.prototype.refresh.apply(this,arguments);

      if( typeof this.options.fixed == "number") {
        var num = this.options.fixed
        this.options.fixed = [num];
      }
      else if( typeof this.options.fixed == "string" || typeof this.options.fixed == "object") {
        if(this.options.fixed.constructor != Array) {
          var selec = this.options.fixed;
          var temparr = [];
          var temp = $(this.element[0]).find(selec);
          var x = this;


          temp.each(function() {
            var i;
            for(i=0;i<x.items.length && x.items[i].item.get(0) != this;++i) {}
            if(i<x.items.length) temparr.push(i);
          });
          this.options.fixed = temparr;
        }
      }   


      //Let's determine if the items are being displayed horizontally
      this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;

      //Let's determine the parent's offset
      this.offset = this.element.offset();

      //Initialize mouse events for interaction
      $.ui.sortable.prototype._mouseInit.apply(this,arguments);
    },

    _mouseCapture: function( event ) { 

      this._fixPrev = this._returnItems();
      return $.ui.sortable.prototype._mouseCapture.apply(this,arguments);
    },

    _mouseStart: function( event ) { 

      for(var i=0;i<this.options.fixed.length;++i) {
        var num = this.options.fixed[i];
        var elem = this.items[num];
        if(event.target == elem.item.get(0)) return false;
      }

      return $.ui.sortable.prototype._mouseStart.apply(this,arguments);
    },

    _rearrange: function(event, i, a, hardRefresh) {

      a ? a[0].appendChild(this.placeholder[0]) : 
      i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));

      this._refix(i);



      //Various things done here to improve the performance:
      // 1. we create a setTimeout, that calls refreshPositions
      // 2. on the instance, we have a counter variable, that get's higher after every append
      // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
      // 4. this lets only the last addition to the timeout stack through



      this.counter = this.counter ? ++this.counter : 1;
      var self = this, counter = this.counter;


      window.setTimeout(function() {
        if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
      },0);

    },

    _refix: function(a) {
      var prev = this._fixPrev;
      var curr = this._returnItems();

      var Fixcodes = this.options.fixed;

      var NoFixed = [];
      var Fixed = [];
      var Mixed = []
      var post = [];


      for(var i=0;i<Fixcodes.length;++i) {
        var fix_index = Fixcodes[i];
        var fix_item  = prev[fix_index];
        var j = 0;

        for(j=0;j<curr.length && curr[j].item.get(0) != fix_item.item.get(0);++j) {}

        curr.splice(j,1);

        Fixed.push(fix_item);
      }

      for(var i=0;i<curr.length;++i) {
        if(curr[i].item.get(0) != this.currentItem.get(0)) {
          NoFixed.push(curr[i]);
        }
      }

      var fix_count = 0;
      var nofix_count = 0;

      for(var i=0;i<Fixed.length + NoFixed.length;++i) {
        if(Fixcodes.indexOf(i) >= 0) {
          Mixed.push(Fixed[fix_count++]);
        }
        else {
          Mixed.push(NoFixed[nofix_count++]);
        }
      }

      var parent = this.currentItem.get(0).parentNode;    
      var allchild = parent.children;

      for(var i=0;i<Mixed.length;++i) {
        parent.removeChild(Mixed[i].item.get(0));
        parent.appendChild(Mixed[i].item.get(0));
      }
    },

    _returnItems: function(event) {

      this.containers = [this];
      var items = [];
      var self = this;
      var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
      var connectWith = $.ui.sortable.prototype._connectWith.apply;

      if(connectWith) {
        for (var i = connectWith.length - 1; i >= 0; i--){
          var cur = $(connectWith[i]);
          for (var j = cur.length - 1; j >= 0; j--){
            var inst = $.data(cur[j], 'sortable');
            if(inst && inst != this && !inst.options.disabled) {
              queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
              this.containers.push(inst);
            }
          };
        };
      }

      for (var i = queries.length - 1; i >= 0; i--) {
        var targetData = queries[i][1];
        var _queries = queries[i][0];

        for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
          var item = $(_queries[j]);

          item.data('sortable-item', targetData); // Data for target checking (mouse manager)

          items.push({
            item: item,
            instance: targetData,
            width: 0, height: 0,
            left: 0, top: 0
          });
        };
      };

      return items;
    },


    value: function(input) {
        //console.log("test");
        $.ui.sortable.prototype.value.apply(this,arguments);
    }
});

})(jQuery);

et de dumping reste de sa réponse, juste au cas

dépendances

https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js

Script

function randomColor() { //for a little fun ;)
   var r = (Math.floor(Math.random()*256));
   var g = (Math.floor(Math.random()*256));
   var b = (Math.floor(Math.random()*256));

   return "#" + r.toString(16) + g.toString(16) + b.toString(16)
}

$(function() {
    $("#sortable1").fixedsortable({
        fixed: "> .static", //you can use css selector
        sort: function() {  //you can add events as well, without getting confused. for example:
            $(".static").css("background",randomColor())  //change the fixed items background
        },
        change: function(event,ui) {
            $(ui.item[0]).css("border","2px solid "+randomColor())  //change the captured border color
        },
        stop: function(event,ui) {
            $(ui.item[0]).css("border","2px solid #777"); //change the back the css modifications
            $("#sortable1 > li.static").css("background","#aaa");
        }
    });

    $("#sortable2").fixedsortable({  //you can use jQuery object as selector
        fixed: $("li[foo]").css("background","red")
    });

    $("#sortable3").fixedsortable({
        fixed: [2,4], //you can use array of zero base indexes as selector
        update: function(event, ui) {
            alert($(this).fixedsortable('toArray'))   //the fixedsortable('toArray') also works
        }
    })

    $("#sortable4").fixedsortable({
        fixed: 5  //you can fix a single item with a simple integer
    })
});

HTML

 <body>
    <div style="width:120px;float:left;">
    <ul id="sortable1">
        <li><a href="#">oranges</a></li>
        <li class="static"><a href="#">apples</a></li>
        <li><a href="#">bananas</a></li>
        <li><a href="#">pineapples</a></li>
        <li><a href="#">grapes</a></li>
        <li class="static"><a href="#">pears</a></li>
        <li><a href="#">mango</a></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>
    </div>
    <div style="width:120px;float:left;">
    <ul id="sortable3">
        <li id="fru_1">bananas</li>
        <li id="fru_2">oranges</li>
        <li id="fru_3" style="background:#f4f">apples</li>
        <li id="fru_4">pineapples</li>
        <li id="fru_5" style="background:#faaba9">grapes</li>
        <li id="fru_6">pears</li>
        <li id="fru_7">mango</li>
    </ul>


    <ul id="sortable4">
        <li>bananas</li>
        <li>oranges</li>
        <li>apples</li>
        <li>pineapples</li>
        <li>grapes</li>
        <li style="background:#dada00">pears</li>
        <li>mango</li>
    </ul>
   </div>
</body>

CSS

ul {margin:10px;}
ul#sortable1 > li, ul#sortable2 > li, ul#sortable3 > li, ul#sortable4 > li {
    display:block;
    width:100px;
    height:15px;
    padding: 3px;
    background: #aaa;
    border: 2px solid #777;
    margin: 1px;
}
ul#sortable1 > li.static {
    opacity:0.5;
}
0
répondu user1778606 2016-01-07 02:43:26

peut-être cela aidera quelqu'un: utilisez les méthodes" disable "et"enable". Exemple HTML:

<ul class="sortable">
  <li>You can move me</li>
  <li data-state="lifeless">You can't move me.</li>
</ul>

Script:

$('#sortable').sortable();
$('#sortable').mousedown(function() {
  if($(this).data('state')=='lifeless') $('#sortable').sortable('disable');
  else $('#sortable').sortable('enable');
});

Live exemple ici: https://jsfiddle.net/ozsvar/0ggqtva5/2/

0
répondu Ozsvar Istvan 2016-06-27 10:59:48