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/

在我的“真实”代码中,我不是只为子级设置一个级别,而是将第二个级别提取<ul>到模板中并递归渲染,效果很好,但我找不到在 JSFiddle 中执行此操作的方法。

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

4

3 回答 3

20

看看这个例子:http: //jsfiddle.net/furf/EJGHX/

我刚刚完成了这个解决方案,所以它还没有被正确记录,但你应该能够为你的解决方案挖掘它。

您将需要使用一些东西:

  1. 指令ezTree- 渲染树
  2. 用于 jQuery UI 的 Manuele J Sarfatti 的 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表达式应该写为item in collection at selectorwhere is the itemiterated child (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>

ui-nested-sortable属性应包含 nestedSortable 插件的 JSON 配置。该插件要求您指定listTypeitems。我的解决方案要求doNotCleartrue. 使用 为事件分配回调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 回答
6

通过 furf 对小提琴进行轻微编辑,使其在 IE 中工作。

当第二个参数为 null 时,IE 在 insertNode 上给出错误,因此在这种情况下,请改用 appendNode。

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

if (!cursor) parentNode.appendChild(cached.element);
else parentNode.insertBefore(cached.element, cursor);

Nested Sortable 插件在 js 中内联,因为 IE 从 github 包含时会出现 MIME 类型不匹配。

于 2013-06-04T01:57:46.527 回答
6

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

于 2014-02-06T04:56:24.223 回答