9

ユーザーが葉をドラッグ アンド ドロップできるツリーのような構造を作成したいと考えています。次のような出発点があります。

HTML

<div ng:controller="controller">
  <ul ui-sortable ng-model="items" ui-options="{connectWith: '.item'}" class="item">
    <li ng-repeat="item in items" class="item">
      {{ item.name }}
      <ul ui-sortable ng-model="item.children" ui-options="{connectWith: '.item'}" class="item">
        <li ng-repeat="item in item.children" class="item">{{ item.name }}</li>
      </ul>
    </li>
  </ul>

  <pre>{{ items | json }}</pre>
</div>

<script src="http://code.angularjs.org/1.0.2/angular.min.js"></script>
<script src="https://raw.github.com/angular-ui/angular-ui/master/build/angular-ui.min.js"></script>

コーヒースクリプト

myapp = angular.module 'myapp', ['ui']

myapp.controller 'controller', ($scope) ->

    $scope.items = [
      {id: 1, name: 'Item 1', children: [
        {id: 5, name: 'SubItem 1.1', children: [
          {id: 11, name: 'SubItem 1.1.1', children: []},
          {id: 12, name: 'SubItem 1.1.2', children: []}
        ]},
        {id: 6, name: 'SubItem 1.2', children: []}
      ]},
      {id: 2, name: 'Item 2', children: [
        {id: 7, name: 'SubItem 2.1', children: []},
        {id: 8, name: 'SubItem 2.2', children: []}
        {id: 9, name: 'SubItem 2.3', children: []}
      ]},
      {id: 3, name: 'Item 3', children: [
        {id: 10, name: 'SubItem 3.1', children: []}
      ]}
    ]

angular.bootstrap document, ['myapp']

コードはこの JSFiddle にもあります: http://jsfiddle.net/bESrf/1/

私の「実際の」コードでは、子のレベルを 1 つだけにする代わりに、2 番目のレベルを<ul>テンプレートに抽出して再帰的にレンダリングしました。これは正常に動作しますが、JSFiddle でそれを行う方法が見つかりませんでした。

それを再帰的にレンダリングし、ng-model によって表されるオブジェクトとサブオブジェクトの配列を変更するドラッグ アンド ドロップを許可する最良の方法は何でしょうか?

4

3 に答える 3

20

この例を見てみましょう: http://jsfiddle.net/furf/EJGHX/

このソリューションを完成させたばかりなので、まだ適切に文書化されていませんが、ソリューションのためにマイニングできるはずです。

いくつかのものを使用する必要があります。

  1. ezTreeディレクティブ - ツリーをレンダリングする
  2. Manuele J Sarfatti の jQuery UI 用の nestedSortable プラグイン
  3. (オプション)uiNestedSortableディレクティブ - テンプレートから nestedSortable を有効にします。
  4. モデルを更新するためのコントローラー コード - を参照してください$scope.update

ezTreeディレクティブの使用

再帰的なデータ構造が与えられた場合:

$scope.data = {
  children: [{
    text: 'I want to create a tree like structure...',
    children: [{
      text: 'Take a look at this example...',
      children: []
    }]
  }]
};

このテンプレートはツリーを構築します:

<ol>
  <li ez-tree="child in data.children at ol">
    <div>{{item.text}}</div>
    <ol></ol>
  </li>
</ol>

ez-tree式は、 は反復された子 (ala)、 はルートレベルのコレクション、 はディレクティブが再帰するテンプレート内のノードの CSS セレクターとして記述されるitem in collection at selector必要itemng-repeatありcollectionますselector。コレクションのターミナル プロパティの名前。childrenこの場合はツリーを再帰するために使用されます。この場合はchild.children. これは構成可能なものに書き直すことができますが、それは読者の演習として残しておきます。

uiNestedSortableディレクティブの使用

<ol ui-nested-sortable="{ listType: 'ol', items: 'li', doNotClear: true }"
  ui-nested-sortable-stop="update($event, $ui)">
</ol>

このui-nested-sortable属性には、nestedSortable プラグインの JSON 構成が含まれている必要があります。プラグインでは、 と を指定する必要がありlistTypeますitems。私の解決策はそれが必要doNotClearですtrue。を使用してコールバックをイベントに割り当てますui-nested-sortable-*eventName*。私のディレクティブは、オプションの $event および $ui 引数をコールバックに提供します。その他のオプションについては、nestedSortable のドキュメントを参照してください。

モデルの更新

この猫の皮を剥ぐ方法は複数あります。これが私のものです。停止イベントでは、要素のスコープの子プロパティを抽出して移動したオブジェクトを特定し、要素の親のスコープの子プロパティを抽出してオブジェクトの移動先を特定し、要素の位置を抽出してオブジェクトの位置を特定します。その目的地で。次に、データ構造を調べて、オブジェクトを元の位置から削除し、新しい位置に挿入します。

$scope.update = function (event, ui) {

  var root = event.target,
    item = ui.item,
    parent = item.parent(),
    target = (parent[0] === root) ? $scope.data : parent.scope().child,
    child = item.scope().child,
    index = item.index();

  target.children || (target.children = []);

  function walk(target, child) {
    var children = target.children,
      i;
    if (children) {
      i = children.length;
      while (i--) {
        if (children[i] === child) {
          return children.splice(i, 1);
        } else {
          walk(children[i], child)
        }
      }
    }
  }
  walk($scope.data, child);

  target.children.splice(index, 0, child);
};
于 2013-01-21T04:36:03.713 に答える