AngularJS - 如何制作一个可拖动的树?

kol*_*rie 9 tree drag-and-drop angularjs

我想创建一个树状结构,用户可以拖放树叶.我的起点如下:

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>
Run Code Online (Sandbox Code Playgroud)

CoffeeScript的

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']
Run Code Online (Sandbox Code Playgroud)

代码也在这个JSFiddle中:http://jsfiddle.net/bESrf/1/

在我的"真实"代码中,我不是只为子级提供一个级别,而是将第二个提取<ul>到一个模板中并递归渲染,这很好用,但我找不到在JSFiddle中执行此操作的方法.

以递归方式呈现它的最佳方法是什么?仍然允许拖放会改变由ng-model表示的对象和子对象的数组?

小智 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: []
    }]
  }]
};
Run Code Online (Sandbox Code Playgroud)

该模板将构建树:

<ol>
  <li ez-tree="child in data.children at ol">
    <div>{{item.text}}</div>
    <ol></ol>
  </li>
</ol>
Run Code Online (Sandbox Code Playgroud)

ez-tree表达式应该写成item in collection at selector其中item是迭代子(ALA ng-repeat),collection是根级别的集合,selector对于其中的指令应该递归的模板中的节点的CSS选择器.在这种情况下,集合的终端属性的名称children将用于递归树child.children.这可以重写为可配置的,但我会将其作为读者的练习.

使用uiNestedSortable指令

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

ui-nested-sortable属性应包含nestedSortable插件的JSON配置.该插件要求您指定listTypeitems.我的解决方案需要doNotCleartrue.使用分配回调事件ui-nested-sortable-*eventName*.我的指令为回调提供了可选的$ event和$ ui参数.有关其他选项,请参阅nestedSortable的文档.

更新您的模型

这种猫的皮肤不止一种方法.这是我的.在stop事件中,它提取元素范围的子属性以确定移动了哪个对象,元素父级范围的子属性以确定对象的目标,以及元素的位置以确定对象的位置在目的地.然后它遍历数据结构并将对象从其原始位置移除并将其插入到新位置.

$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);
};
Run Code Online (Sandbox Code Playgroud)


小智 6

由furf轻微编辑小提琴,使其在IE中工作.

当第二个参数为null时,IE在insertNode上给出错误,因此在这种情况下使用appendNode代替.

http://jsfiddle.net/michieljoris/VmtfR/

if (!cursor) parentNode.appendChild(cached.element);
else parentNode.insertBefore(cached.element, cursor);
Run Code Online (Sandbox Code Playgroud)

嵌套的可排序插件在js中内联,因为当从github包含时,IE提供MIME类型不匹配.


Jim*_*Liu 6

尝试使用Angular-NestedSortable,它是一个Angularjs插件,可以对嵌套列表进行排序并绑定数据,而不需要依赖于jQuery. https://github.com/jimliu/Angular-NestedSortable