我想创建一个树状结构,用户可以拖放树叶。我的起点如下:
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>
的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']
代码也在这个JSFiddle中:http://jsfiddle.net/bESrf/1/
在我的“真实”代码中,我将第二个<ul>
提取到一个模板并递归渲染,而不是只有一个级别的子代码,这很好,但我找不到办法它在JSFiddle中。
递归渲染它的最佳方法是什么?仍然允许拖放,这会改变由ng-model表示的对象和子对象的数组?
答案 0 :(得分:20)
看一下这个例子:http://jsfiddle.net/furf/EJGHX/
我刚刚完成了这个解决方案,因此尚未正确记录,但您应该能够将其解决。
你需要使用一些东西:
ezTree
指令 - 渲染树uiNestedSortable
指令 - 从模板启用nestedSortable。 $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 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>
ui-nested-sortable
属性应包含nestedSortable插件的JSON配置。该插件要求您指定listType
和items
。我的解决方案要求doNotClear
为true
。使用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);
};
答案 1 :(得分:6)
使用furf轻微编辑小提琴,使其在IE中运行。
IE在第二个参数为null时在insertNode上给出错误,所以在这种情况下使用appendNode代替。
http://jsfiddle.net/michieljoris/VmtfR/
if (!cursor) parentNode.appendChild(cached.element);
else parentNode.insertBefore(cached.element, cursor);
嵌套可排序插件在js中内联,因为IE在github中包含MIME类型不匹配。
答案 2 :(得分:6)
尝试使用Angular-NestedSortable,它是一个Angularjs插件,可以对嵌套列表进行排序并绑定数据,而不需要依赖于jQuery。 https://github.com/jimliu/Angular-NestedSortable