2015-11-03 11 views
5

用アンギュラドラッグアンドドロップI Iは、ユーザーが/リストとドラッグからオブジェクトを選択し、特定のスロットにドロップできるようにする必要があり、次のような状況があります。組み合わせるAngularJS、jQueryUI、ソートされたリスト

enter image description here

オブジェクトは、スロットの1〜3倍のサイズにすることができます。したがって、ユーザーがオブジェクト1をスロット0にドラッグすると、スロット0(startSlot = 0およびendSlot = 0)のみを占有します。しかし、ユーザーがオブジェクト3をスロット3にドラッグすると、スロット3,4,5(startSlot = 3およびendSlot = 5)を占有します。

オブジェクトをスロットにドロップすると、オブジェクトをクリックしてスロット内で上下にドラッグすることで、オブジェクトの順序を変更できます。オブジェクトは、互いに重複することはできません。

enter image description here

私は角使用していますので、私は、データベースからオブジェクトのリストを読んでいると私はスロットの数のための変数を持っています。私はいくつかの解決策を試みました。私は、ドラッグドロップ可能jQueryとjQueryUIの使用を信じて、そしてソート可能はソリューションの一部で、ここではドラッグ/ドロップとソート可能性を示す最初のフィドルは次のとおりです。

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

このフィドルの問題は、私はセットを必要とするということですスロット数。オブジェクトがスロットに配置されると、オブジェクトのサイズに応じて1〜3つのスロットが置き換えられます。下の2番目のバイオリンはAngularJSを統合:

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

ここでの問題は、私は私が一度オブジェクトリストからドラッグして、オブジェクトをスナップするグリッドのいくつかのタイプを必要と知っていることです。私が探している結果は、それらの割り当てられたスロット内のオブジェクトのJSONリストである:

[{ID:OBJ1、startSlot:0、endSlot:0}、{ID:OBJ3、startSlot:3、endSlot :5}]

私も解決策がここにありcodf0rmerの角度ドラッグ&ドロップが必要になると確信している:

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

しかし、私はそれをテストするために私のバイオリンに統合取得しようとして問題を抱えています。これは私がしばらくの間旋回してきた面白い挑戦です。もし誰でも援助を受けることができれば大いに感謝します。御時間ありがとうございます。

+0

一般的なAngularUIスイートの一部であるhttps://github.com/angular-ui/ui-sortableをご覧ください。彼らは接続されたリストをサポートしていますが、あなたのアイテムサイズの要件は、おそらくリスト項目の顧客の扱いを必要とするでしょうが、イベントを使用するときは直感的でなければなりません。私は前にプロジェクトの中でうまく使用しました。残念ながら、私は今あなたの特定の要件を調べる時間がありません。 – Beyers

+0

HTML 5ドラッグ&ドロップAPIを使用してカスタムモジュールを作成することもできます。その実装は非常に簡単です。 – malinkody

答えて

5

HTML5ドラッグ&ドロップAPIとjQueryを使用して、要件の基本的な実装を開始しました。 APIは軽量であり、サードパーティのスクリプトを必要としません。コードは簡単にカスタマイズできます。提供されたサンプルは出発点に過ぎず、決して生産準備ができていないので、最適化し、使用前にjQueryプラグインモジュールに変換する必要があります。これにより、モジュールの再利用性が向上します。

コメントのコードに関するご質問はお待ちしております。

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> 

ジャバスクリプトソートなし:

(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; 
} 

編集:次のスクリプトにもソートが追加されています。私はこの例をテストしてストレスを感じておらず、特定の条件下では実行できないかもしれません。

(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

これは素晴らしいことですが、私は「こんにちは」を乗り越えて顧客に解決策を提供する必要がありました。フィドルは完璧です、もう一度あなたの助けに感謝します。 –