jQuery ordenable: selecciona y arrastra varios elementos de la lista

Tengo un diseño donde tengo una lista de “cajas disponibles”, los usuarios toman cajas arrastrándolas desde la lista de “cajas disponibles” a su lista “Mis cajas”.

Los usuarios a menudo toman múltiples cajas a la vez (máximo 20), una vez que han terminado con los recuadros, los arrastran nuevamente a la lista de “recuadros disponibles” para devolverlos.

jQuery ordenable me permite arrastrar un cuadro a la vez que, desde la perspectiva del usuario, no es deseable. No he podido encontrar una solución simple al problema.

Puede que tenga que idear un método de IU diferente por completo, pero primero ¿alguien tiene alguna sugerencia sobre cómo se podría lograr esto?

¡Gracias!

No tengo esto funcionando usando ordenable, pero lo hice usando arrastrar y soltar. No sé si cubrí toda la funcionalidad que necesita, pero debería ser un buen comienzo ( demostración aquí ):

HTML

Available Boxes (click to select multiple boxes)

  • Box #1
  • Box #2
  • Box #3
  • Box #4

My Boxes

Guión

 $(document).ready(function(){ var selectedClass = 'ui-state-highlight', clickDelay = 600, // click time (milliseconds) lastClick, diffClick; // timestamps $("#draggable li") // Script to deferentiate a click from a mousedown for drag event .bind('mousedown mouseup', function(e){ if (e.type=="mousedown") { lastClick = e.timeStamp; // get mousedown time } else { diffClick = e.timeStamp - lastClick; if ( diffClick < clickDelay ) { // add selected class to group draggable objects $(this).toggleClass(selectedClass); } } }) .draggable({ revertDuration: 10, // grouped items animate separately, so leave this number low containment: '.demo', start: function(e, ui) { ui.helper.addClass(selectedClass); }, stop: function(e, ui) { // reset group positions $('.' + selectedClass).css({ top:0, left:0 }); }, drag: function(e, ui) { // set selected group position to main dragged object // this works because the position is relative to the starting position $('.' + selectedClass).css({ top : ui.position.top, left: ui.position.left }); } }); $("#droppable, #draggable") .sortable() .droppable({ drop: function(e, ui) { $('.' + selectedClass) .appendTo($(this)) .add(ui.draggable) // ui.draggable is appended by the script, so add it after .removeClass(selectedClass) .css({ top:0, left:0 }); } }); }); 

Solución de trabajo

tl; dr : Consulte este violín para obtener una respuesta funcional .


Busqué en todas partes una solución para el problema de arrastrar múltiples elementos seleccionados desde un ordenable a un ordenable conectado , y estas respuestas fueron las mejores que pude encontrar.

Sin embargo…

La respuesta aceptada es incorrecta , y la respuesta de @ Shanimal está cerca , pero no del todo completa. Tomé el código @ Shanimal y lo construí.

Lo arreglé:

  • el error de elemento de la lista que desapareció que @Ryan mencionó ,
  • limpió los errores de syntax en el HTML (tags de cierre faltantes y
  • s nesteds).

Yo añadí:

  • Soporte adecuado Ctrl + clic (o Cmd + clic si en un mac) para seleccionar varios elementos. Hacer clic sin la tecla Ctrl presionada hará que ese elemento seleccionado, y otros elementos en la misma lista sean deseleccionados . Este es el mismo comportamiento de clic que el widget jQuery UI Selectable() , con la diferencia de que Selectable() tiene una marquesina en mousedrag.

Violín

HTML:

 
  • One
  • Two
  • Three
  • Four
  • Five
  • Six

JavaScript (con jQuery y jQuery UI):

 $("ul").on('click', 'li', function (e) { if (e.ctrlKey || e.metaKey) { $(this).toggleClass("selected"); } else { $(this).addClass("selected").siblings().removeClass('selected'); } }).sortable({ connectWith: "ul", delay: 150, //Needed to prevent accidental drag when trying to select revert: 0, helper: function (e, item) { var helper = $('
  • '); if (!item.hasClass('selected')) { item.addClass('selected').siblings().removeClass('selected'); } var elements = item.parent().children('.selected').clone(); item.data('multidrag', elements).siblings('.selected').remove(); return helper.append(elements); }, stop: function (e, info) { info.item.after(info.item.data('multidrag')).remove(); } });

    NOTA:

    Desde que publiqué esto, implementé algo similar, conectando elementos de lista arrastrables a una clasificación, con capacidad de selección múltiple. Está configurado casi exactamente igual, ya que los widgets de jQuery UI son muy similares. Una sugerencia de UI es asegurarse de tener el parámetro de delay establecido para los juegos de arrastrar o seleccionables, de modo que puede hacer clic para seleccionar varios elementos sin iniciar un arrastre. Luego construyes un helper que se parece a todos los elementos seleccionados juntos (crea un nuevo elemento, clonas los elementos seleccionados y los anexas), pero asegúrate de dejar intacto el elemento original (de lo contrario, se estropea la funcionalidad, no puedo decir exactamente por qué, pero implica muchas frustrantes excepciones DOM).

    También agregué la funcionalidad Shift + Click , para que funcione más como aplicaciones de escritorio nativas. Debería comenzar un blog para exponerlo con mayor detalle 🙂

    JSFiddle: http://jsfiddle.net/hQnWG/

      

    Click items to select them

    • One
    • Two
    • Three
    • Four
    • Five
    • Six

    Hay un complemento jQuery UI para eso: https://github.com/shvetsgroup/jquery.multisortable

    jsFiddle: http://jsfiddle.net/neochief/KWeMM/

     $('ul.sortable').multisortable(); 

    La solución de Aaron Blenkush tiene una falla importante: eliminar y agregar elementos a la estructura de listas ordenables rompe la estructura; la actualización puede ayudar, pero si otras funciones procesan la lista, se necesita un desencadenante para todas ellas y todo se vuelve demasiado complejo.

    Después de analizar algunas soluciones en stackoverflow, he resumido el mío en lo siguiente:

    No use helper – use la función de inicio, porque ya tiene ui.item, que es el helper por defecto.

      start: function(event, ui){ // only essential functionality below // get your own dragged items, which do not include ui.item; // the example shows my custom select which selects the elements // with ".selected" class var dragged = ui.item.siblings(arr["nested_item"]).children('.tRow.tSelected').parent(arr["nested_item"]); // clone the dragged items var dragged_cloned = dragged.clone(); // add special class for easier pick-up at update part dragged_cloned.each(function(){$(this).addClass('drag_clone');}); // record dragged items as data to the ui.item ui.item.data('dragged', dragged); // hide dragged from the main list dragged.hide(); // attached cloned items to the ui.item - which is also ui.helper dragged_cloned.appendTo(ui.item); }, 
    1. En la parte de actualización:

       update: function(event, ui){ // only essential functionality below // attach dragged items after the ui.item and show them ui.item.after(ui.item.data("dragged").show()); // remove cloned items ui.item.children(".drag_clone").remove(); }, 

    La función de detención puede necesitar una copia de la funcionalidad de actualización, pero es probable que esté separada de la actualización, porque si no hay cambio, no envíe nada al servidor.

    Para agregar: conservar el orden de los elementos arrastrados.