web-dev-qa-db-fra.com

Listes de tri JQuery et éléments fixes/verrouillés

Est-il possible de verrouiller les éléments de la liste dans la liste triable JQuery de manière à ce qu'ils restent à cet endroit particulier de la liste.

Par exemple, 

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

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

Donc, j'aimerais que les éléments B, C et G soient corrigés de manière à ce que si l'utilisateur glisse et dépose l'élément D au début de la liste, l'élément A "saute" sur les éléments fixes/verrouillés B et C avec les résultats suivants ...

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

Je cherche quelque chose comme ça sans chance. C'est possible..?

30
laroma

J'ai étendu le jQuery.Ui.sortable:

Vue d'ensemble

jQuery.Ui.sortable extension du widget avec la fonction fixed. Cette fonctionnalité permet à l'utilisateur de corriger les éléments de la liste.
Avec le constructeur .fixedsortable(), vous construisez une classe .sortable() qui est étendue aux fonctionnalités. Vous pouvez également utiliser les méthodes original et extended .

Code

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

Exemple

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

Usage

Général:

Pour l'utiliser, ajoutez la propriété fixed à la liste des options de tri:

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

la valeur peut être:

  • entier exemple: 3
  • array of integer exemple: [1,2,5]
  • un élément html ou une liste d'éléments html
  • a 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
    })
});

Remarques:

Si vous insistez pour utiliser le .sortable au lieu de .fixedsortable, vous pouvez utiliser cette https://Gist.github.com/3758329#file_sortable.js à la place de la bibliothèque jquery.ui. C'est un remplacement complet du jQuery.ui, mais je ne recommande pas de l'utiliser à cause de mises à jour ultérieures.

_ {Je travaille dessus depuis plus de 12 heures :( je suis fou ..

26

Voici une version, espérons-le-sans-bug, mise à jour que vous faites glisser. Il génère les positions souhaitées actuelles des éléments lorsque le tri commence, ce qui signifie que vous devriez pouvoir modifier les classes à tout moment, actualiser les éléments de la liste du widget et continuer.

Il utilise également la propriété intégrée items du triable pour empêcher le déplacement des éléments fixes et pour résoudre les problèmes de tri en haut et en bas de la liste.

J'ai essayé de déplacer les éléments fixes, mais cela s'est traduit par un comportement horriblement problématique, en particulier lorsqu'il y a plusieurs éléments fixes dans des groupes. La solution finale détache tous les éléments fixes de la liste, ajoute un élément d'assistance à l'avant, puis réinsère les éléments fixes à la position souhaitée, ce qui semble corriger tous les bogues.

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();
    }
});
57
DarthJDG

Vérifiez ceci: Forcer un élément à rester en place dans une liste triable de jQuery UI

De plus, j'ai implémenté la solution ci-dessus avec plusieurs éléments fixes ici: http://jsfiddle.net/enBnH/12/ (obsolète, voir ci-dessous) C'est assez explicite, je pense .

MODIFIER:

J'ai automatisé le processus de génération des valeurs lockto ainsi que l'ajout d'ID à ces lis avec la classe "fixed" (notez que je dois ajouter un ID afin que nous puissions le référencer)

Voir la solution COMPLETE ICI: http://jsfiddle.net/enBnH/44/ //strike>

MODIFIER

D'accord, après quelques milliards d'erreurs avec ce qui précède, je viens de réécrire moi-même le problème: http://jsfiddle.net/thomas4g/GPMZZ/15/

NOTE: Ce qui précède fonctionne, mais la réponse de @DarthJDG me semble beaucoup plus agréable. Je laisse les miens de côté, quelqu'un pourrait préférer son comportement (j'ai appris à ne pas supprimer des choses simplement parce qu'il existe une meilleure version: P)

8
Thomas Shields

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 souhaitez verrouiller uniquement la 1ère ligne, vous pouvez le faire:

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

Les possibilités sont infinies...

3
Leniel Maccaferri

Ceci est basé sur le code @DarthJDG. Cependant, il ne récupérait pas tous les identifiants 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 conserve l'identifiant 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
sarunast

Sortables et objets fixes connectés

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

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
Ilya Shashilov

Peut-être que 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>

Scénario:

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

Exemple en direct ici: https://jsfiddle.net/ozsvar/0ggqtva5/2/

0
Ozsvar Istvan

oh non! Le lien Gist est cassé. voici le dump de code de https://Gist.github.com/peterh-capella/4234752

code consulté le 6 janvier 2016

//this code is created to fix this problem: http://stackoverflow.com/questions/4299241/

(function( $, undefined ) {

$.widget("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 vider le reste de sa réponse, juste au cas où

les dépendances

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

Scénario

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
user1778606