2015-11-03 10 views
5

ho la seguente situazione in cui ho bisogno per consentire all'utente di selezionare gli oggetti da un elenco e drag/farli cadere in un certo fessura:AngularJS combinazione, jQueryUI, angolare-drag-drop per la lista ordinata

enter image description here

Gli oggetti possono essere da una a tre volte le dimensioni di uno slot. Quindi, se un utente trascina l'oggetto 1 nello slot 0, occupa solo lo slot 0 (startSlot = 0 e endSlot = 0). Tuttavia, se un utente trascina l'oggetto 3 nello slot 3, occupa gli slot 3, 4 e 5 (startSlot = 3 e endSlot = 5).

Una volta che gli oggetti vengono rilasciati negli slot, un utente può riordinare gli oggetti facendo clic e trascinando gli oggetti su e giù negli slot. Gli oggetti non possono sovrapporsi l'un l'altro:

enter image description here

Sto usando angolare, così sto leggendo un elenco di oggetti da un database e ho una variabile per il numero di slot. Ho provato un paio di soluzioni. Credo che l'uso di jQuery e jQueryUI trascinabili, droppable, e ordinabile è parte della soluzione, qui è il primo violino dimostrando drag/drop e ordinabile:

http://jsfiddle.net/mduvall216/6hfuzvws/4/ 

Il problema di questo violino è che ho bisogno di un set numero di slot. Una volta che un oggetto viene inserito negli slot, sostituisce da 1 a 3 slot in base alle dimensioni dell'oggetto. Il secondo violino sotto integra AngularJS:

http://jsfiddle.net/mduvall216/zg5x4b6k/4/ 

Il problema qui è che so che ho bisogno di qualche tipo di griglia per scattare gli oggetti da trascinati volta dall'elenco degli oggetti. Il risultato che sto cercando è una lista di oggetti JSON nei loro slot assegnati:

[{id: obj1, startSlot: 0, endSlot: 0}, {id: obj3, startSlot: 3, endSlot : 5}]

sono anche sicuro che la soluzione avrebbe bisogno di angolare di trascinamento del codf0rmer trova qui:

https://github.com/codef0rmer/angular-dragdrop 

ma sto avendo problemi cercando di ottenere che integrato in mio violino per testare . Questa è una sfida interessante su cui sto girando da un po ', se qualcuno può essere d'aiuto sarebbe molto apprezzato. Grazie per il tuo tempo.

+0

Dai un'occhiata a https://github.com/angular-ui/ui-sortable, che fa parte della popolare suite di componenti AngularUI. Supportano gli elenchi connessi, ma il requisito relativo alle dimensioni degli articoli probabilmente richiederà la gestione da parte del cliente degli elementi dell'elenco, ma dovrebbe essere semplice quando si utilizzano gli eventi. L'ho usato con successo all'interno di un progetto prima. Purtroppo non ho tempo ora per esaminare le vostre esigenze specifiche. – Beyers

+0

È inoltre possibile creare un modulo personalizzato utilizzando l'API di trascinamento e rilascio HTML 5. È abbastanza facile da implementare. – malinkody

risposta

5

Ho avviato un'implementazione di base dei requisiti utilizzando l'API di rilascio HTML5 Drag e jQuery &. L'API è leggera e non richiede script di terze parti. Il codice dovrebbe essere facile da personalizzare. L'esempio fornito è solo un punto di partenza e non è affatto pronto per la produzione e dovrebbe essere ottimizzato e possibilmente trasformato in un modulo plugin jQuery prima dell'uso. Ciò aumenterebbe la riutilizzabilità del modulo.

Invia eventuali ulteriori domande sul codice nei commenti.

JSFiddle Example without sortable:

JSFiddle with sortable

html:

<ul class="select-list"> 
    <li class="header">Object List</li> 
    <li data-slots="1" class="s1">Object 1</li> 
    <li data-slots="2" class="s2">Object 2</li> 
    <li data-slots="3" class="s3">Object 3</li> 
</ul> 
<ul class="drop-list" id="sortable"> 
    <li>Slot 1</li> 
    <li>Slot 2</li> 
    <li>Slot 3</li> 
    <li>Slot 4</li> 
    <li>Slot 5</li> 
    <li>Slot 6</li> 
    <li>Slot 7</li> 
    <li>Slot 8</li> 
    <li>Slot 9</li> 
    <li>Slot 10</li> 
    <li>Slot 11</li> 
    <li>Slot 12</li> 
    <li>Slot 13</li> 
</ul> 

javascript senza ordinabile:

(function ($, undefined) { 
    // document ready function 
    $(function() { 
     init(); 

     $('ul.select-list').on({ 
      'dragstart': dragstart, 
       'dragend': dragend 
     }, 'li'); 

     $('ul.drop-list').on({ 
      'dragenter dragover': dragover, 
       'dragleave': dragleave, 
       'drop': drop 
     }, 'li.dropzone'); 
    }); 

    // Initializes the lists 
    function init() { 
     $('ul.select-list').find('li').not('[class="header"]').each(function() { 
      var height = getSlotHeight() * $(this).data('slots'); 
      $(this).height(height); 
     }).attr('draggable', true); 

     $('ul.drop-list').find('li').each(function() { 
      $(this).height(getSlotHeight()); 
     }).addClass('dropzone'); 
    } 

    // Get the height of grid slots 
    function getSlotHeight() { 
     return 20; 
    } 

    /** 
    * Checks whether target is a kompatible dropzone 
    * A dropzone needs the dropzone class 
    * and needs to have enough consequent slots to drop the object into 
    */ 
    function isDropZone(target, draggedObj) { 
     var isDropZone = true; 
     var slots = draggedObj.data('slots'); 
     for (var i = 1; i < slots; i++) { 
      target = target.next(); 
      if (target.size() == 0 || !target.hasClass('dropzone')) { 
       isDropZone = false; 
       break; 
      } 
     } 
     return isDropZone; 
    }  

    /* 
    * The following events are executed in the order the handlers are declared 
    * dragstart being first and dragend being last 
    */ 

    // dragstart event handler 
    function dragstart(e) { 
     e.stopPropagation(); 
     var dt = e.originalEvent.dataTransfer; 
     dt.effectAllowed = 'move'; 
     dt.setData('text/html', ''); 
     $('ul.select-list').data({ 
      draggedObj: $(this) 
     }); 
    } 

    // dragover event handler 
    function dragover(e) { 
     e.preventDefault(); 
     e.stopPropagation(); 
     var data = $('ul.select-list').data(); 
     if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) { 
      e.originalEvent.dataTransfer.dropEffect = 'none'; 
      return; 
     } 
     e.originalEvent.dataTransfer.dropEffect = 'move'; 
     var item = $(this).addClass('dragover'); 
     var slots = data.draggedObj.data('slots'); 
     for (var i = 1; i < slots; i++) { 
      item = item.next('li').addClass('dragover'); 
     } 
     return false; 
    } 

    // dragleave event handler 
    function dragleave(e) { 
     e.preventDefault(); 
     e.stopPropagation(); 
     var data = $('ul.select-list').data(); 
     if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) { 
      return; 
     } 
     var item = $(this).removeClass('dragover'); 
     var slots = data.draggedObj.data('slots'); 
     for (var i = 1; i < slots; i++) { 
      item = item.next('li').removeClass('dragover'); 
     } 
     return false; 
    } 

    // drop event handler 
    function drop(e) { 
     e.stopPropagation(); 
     e.preventDefault(); 
     var data = $('ul.select-list').data(); 
     if (data.draggedObj || !isDropZone($(this), data.draggedObj)) { 
      data.target = $(this); 
      data.draggedObj.trigger('dragend'); 
     } 
     return false; 
    } 

    // dragend event handler 
    function dragend(e) { 
     var data = $('ul.select-list').data(); 
     if (data.draggedObj && data.target && isDropZone(data.target, data.draggedObj)) { 
      var item = data.target.hide(); 
      var slots = data.draggedObj.data('slots'); 
      for (var i = 1; i < slots; i++) { 
       item = item.next('li').hide(); 
      } 
      data.target.before(data.draggedObj); 
     } 

     data.target = undefined; 
     data.draggedObj = undefined; 
     $('ul.drop-list').find('li').removeClass('dragover'); 
    } 
}(jQuery)); 

css:

ul { 
    list-style-type: none; 
    margin: 0; 
    padding: 0; 
    float: left; 
} 
li { 
    width: 150px; 
} 
li.header { 
    height:20px; 
    font-weight:bold; 
} 
.select-list li { 
    margin-bottom: 10px; 
} 
.drop-list { 
    margin-left:20px; 
} 
.drop-list li { 
    background-color: #ccc; 
    border-left: 1px solid black; 
    border-right: 1px solid black; 
    border-top: 1px solid black; 
} 
.drop-list li.dragover { 
    background-color:#fff; 
} 
.drop-list li:last-child { 
    border-bottom: 1px solid black; 
} 
li.s1 { 
    background-color: #FFE5E5; 
} 
li.s2 { 
    background-color: #C6D4FF; 
} 
li.s3 { 
    background-color: #C6FFE3; 
} 

Modifica: al seguente script è stato aggiunto anche l'ordinamento. Non ho stressato testato questo esempio e potrebbe non funzionare in determinate condizioni.

(function ($, undefined) { 
    // document ready function 
    $(function() { 
     init(); 

     $('ul.select-list,ul.drop-list').on({ 
      'dragstart': dragstart, 
       'dragend': dragend 
     }, 'li.object').on('dragenter dragover', listDragover); 

     $('ul.drop-list').on({ 
      'dragenter dragover': dragover, 
       'dragleave': dragleave, 
       'drop': drop 
     }, 'li.dropzone'); 
    }); 

    // Initializes the lists 
    function init() { 
     $('ul.select-list').find('li').not('[class="header"]').each(function() { 
      var height = getSlotHeight() * $(this).data('slots'); 
      $(this).height(height); 
     }).attr('draggable', true).addClass('object'); 

     $('ul.drop-list').find('li').each(function() { 
      $(this).height(getSlotHeight()); 
     }).addClass('dropzone'); 
    } 

    // Get the height of the grid 
    function getSlotHeight() { 
     return 20; 
    } 

    /** 
    * Checks whether target is a kompatible dropzone 
    * A dropzone needs the dropzone class 
    * and needs to have enough consequent slots to drop the object into 
    */ 
    function isDropZone(target, draggedObj) { 
     var isDropZone = true; 
     var slots = draggedObj.data('slots'); 
     for (var i = 1; i < slots; i++) { 
      target = target.next('li'); 
      if (target.size() == 0 || !target.hasClass('dropzone')) { 
       if (!target.is(draggedObj)) { 
        isDropZone = false; 
        break; 
       } else { 
        i--; 
       } 
      } 
     } 
     return isDropZone; 
    } 

    // dragstart event handler 
    function dragstart(e) { 
     e.stopPropagation(); 
     var dt = e.originalEvent.dataTransfer; 
     dt.effectAllowed = 'move'; 
     dt.setData('text/html', ''); 
     $('ul.select-list').data({ 
      draggedObj: $(this) 
     });   
    } 

    // dragover list event handler 
    function listDragover(e) { 
     e.preventDefault(); 
     e.stopPropagation(); 
     e.originalEvent.dataTransfer.dropEffect = 'none'; 
     var data = $('ul.select-list').data(); 
     if (data.draggedObj) { 
      var item = data.draggedObj; 
      item.hide(); 
      if (data.draggedObj.closest('ul').is('ul.drop-list')) { 
       var slots = item.data('slots'); 
       for (var i = 0; i < slots; i++) { 
        item = item.next('li').show(); 
       } 
      } 
     } 
     return false; 
    } 

    // dragover event handler 
    function dragover(e) { 
     e.preventDefault(); 
     e.stopPropagation(); 
     var data = $('ul.select-list').data(); 
     if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) { 
      e.originalEvent.dataTransfer.dropEffect = 'none'; 
      return; 
     } 
     e.originalEvent.dataTransfer.dropEffect = 'move'; 
     var item = $(this).addClass('dragover'); 
     var slots = data.draggedObj.data('slots'); 
     for (var i = 1; i < slots; i++) { 
      item = item.next('li'); 
      if (!item.is(data.draggedObj)) { 
       item.addClass('dragover'); 
      } else { 
       i--; 
      } 
     } 
     return false; 
    } 

    // dragleave event handler 
    function dragleave(e) { 
     e.preventDefault(); 
     e.stopPropagation(); 
     var data = $('ul.select-list').data(); 
     if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) { 
      return; 
     } 
     var item = $(this).removeClass('dragover'); 
     var slots = data.draggedObj.data('slots'); 
     for (var i = 1; i < slots; i++) { 
      item = item.next('li'); 
      if (!item.is(data.draggedObj)) { 
       item.removeClass('dragover'); 
      } else { 
       i--; 
      } 
     } 
     return false; 
    } 

    // drop event handler 
    function drop(e) { 
     e.stopPropagation(); 
     e.preventDefault(); 
     var data = $('ul.select-list').data(); 
     if (data.draggedObj || !isDropZone($(this), data.draggedObj)) { 
      data.target = $(this); 
      data.draggedObj.trigger('dragend'); 
     } 
     return false; 
    } 

    // dragend event handler 
    function dragend(e) { 
     var data = $('ul.select-list').data(); 
     var target = data.target; 
     if (data.draggedObj && !target && data.draggedObj.closest('ul').is('ul.drop-list')) { 
      target = data.draggedObj.next('li'); 
     } 
     if (data.draggedObj && target && isDropZone(target, data.draggedObj)) { 
      data.draggedObj = data.draggedObj.insertBefore(target); 
      var item = target.hide(); 
      var slots = data.draggedObj.data('slots'); 
      for (var i = 1; i < slots; i++) { 
       item = item.next('li').hide(); 
      } 
     } 
     if (data.draggedObj) { 
      data.draggedObj.show(); 
     } 
     data.target = undefined; 
     data.draggedObj = undefined; 
     $('ul.drop-list').find('li').removeClass('dragover'); 
    } 
}(jQuery)); 
+0

questo è fantastico, proprio quello di cui avevo bisogno per superare la "gobba" e fornire una soluzione ai nostri clienti. Il violino è perfetto, grazie ancora per il tuo aiuto. –

Problemi correlati