因为项目里要用到树形插件做个下拉的机构选择树形图,开始想到了angular-ui-tree,但是因为数据格式和我的数据格式不是很匹配,所以就弃用了,在github上找了另外一个,也就是今天的主角:angular-tree-dnd(https://github.com/thienhung1989/angular-tree-dnd)。
先说说数据格式的问题,说到树形图,很多人脑子里出现的数据格式可能就是子节点套在父节点里面,子子节点再套在子节点里面,一层一层嵌套下去,这样的数据格式阅读起来结构是比较清晰,做成树形图的话依赖angular-ui-tree会比较好,下面是这种数据格式:
{
"id": 1,
"title": "node1",
"nodes": []
}
还有一种数据格式是通过parent_id来确定父子节点对应关系,而我现在的项目的数据格式就是这种:
[
{
"DemographicId": 1,
"ParentId": null,
"Name": "United States of America",
"Description": "United States of America",
"Area": 9826675,
"Population": 318212000,
"TimeZone": "UTC -5 to -10"
},
{
"DemographicId": 2,
"ParentId": 1,
"Name": "California",
"Description": "The Tech State",
"Area": 423970,
"Population": 38340000,
"TimeZone": "Pacific Time"
}
]
就是通过DemographicId和ParentId来找到父子节点的对应关系,具体的angular-tree-dnd使用方法如下:
1.安装依赖:
bower install angular-tree-dnd
2.依赖注入:
angular.module('zyClient',['zyClient.directives','ntt.TreeDnD'])
3.在你的控制器注入$TreeDnDConvert(用于转换id和parentId,下面会说到):
ResourceControlCtrl = ['$scope','$TreeDnDConvert', ($scope, $TreeDnDConvert)
4.页面的搭建:
tree-dnd(
tree-class="dnd"
tree-control="my_tree"
tree-data="tree_data"
column-defs="col_defs"
indent="30"
indent-plus="20"
indent-unit="px"
)
5.控制器数据的处理:
$scope.tree_data=$TreeDnDConvert.line2tree($scope.list, 'id', 'parent_id')
这里也就是将父子节点的对应关系设置成id和parent_id,因为后端给你的数据不可能像是上述中的数据格式那样是DemographicId和ParentId,这个就是根据你的实际数据格式去转换了。
接下来就要注意坑点了,github上给出的文档是节点是支持点击和选择事件的,分别是on-select和on-click
<tree-dnd
tree-class="dnd"
tree-data="tree_data"
tree-control="my_tree"
callbacks="callbacks"
drag-enabled="true"
icon-leaf="none"
icon-expand="fa fa-fw fa-angle-right"
icon-collapse="fa fa-fw fa-angle-down"
template-url="tree-dnd-template.html"
column-defs="col_defs"
expand-on="expanding_property"
on-select="my_tree_handler(node)"
on-click="my_tree_handler(node)"
data-indent="30"
data-indent-unit="px"
data-indent-plus="15"
>
</tree-dnd>
而在我的实际使用中,大家也可以看到我的页面上并没有事件,原因是因为我加了事件并没有起到任何作用,也就是事件是失效的,这让我找了很久的文档,也没有发现有什么问题,开始以为是模板的问题,但是文档上很清楚的表示如果不传template-url也是有默认文档的,实在是找不出是什么原因导致事件失效,后来只好查看了源码:
$scope.onClick = function (node) {
if (angular.isDefined($scope.tree) && angular.isFunction($scope.tree.on_click)) {
// We want to detach from Angular's digest cycle so we can
// independently measure the time for one cycle.
setTimeout(
function () {
$scope.tree.on_click(node);
}, 0
);
}
};
$scope.onSelect = function (node) {
if (angular.isDefined($scope.tree)) {
if (node !== $scope.tree.selected_node) {
$scope.tree.select_node(node);
}
if (angular.isFunction($scope.tree.on_select)) {
setTimeout(
function () {
$scope.tree.on_select(node);
}, 0
);
}
}
};
这是源码378行到404行的内容,我们可以很清楚看到事件是封装了的,但是我们再看看3348行默认的模板里TreeDnD.html是没有onClick的点击事件的,只有一个onSelect的事件,那我们在使用默认模板的时候当然也就没有办法使用onClick的事件。
既然onClick不行,那onSelect总该行吧,然而事实是绑在指令上的on-select=”select(node)”的事件也执行不了,这下就更懵了,结果看了一下onSelect事件的封装:
$scope.onSelect = function (node) {
if (angular.isDefined($scope.tree)) {
if (node !== $scope.tree.selected_node) {
$scope.tree.select_node(node);
}
if (angular.isFunction($scope.tree.on_select)) {
setTimeout(
function () {
$scope.tree.on_select(node);
}, 0
);
}
}
};
可以看到是必须是$scope.tree上绑定on_select,注意是on_select,格式要完全一样才可以调用,那我的控制器里的函数就是:
$scope.my_tree.on_select = (org) ->
$scope.m.org = org
$scope.showOrgone = false
$scope.$apply()
if m.role is 1
_getSuperResourceStatic(org)
else
_getRoleResourceStatic(org)
return
到这一步事件才算能正常调用,其实挺坑的,没有使用之前如果知道这么坑也就不会再用了,github确实是个好地方,很多开源的框架的组件可以供我们使用,但是开源的坏处就是很多项目参差不齐,很可能不是很成熟就放出来供大家使用,这就会导致我们会遇到很多意想不到的坑,不过只要一点一点去看,大部分还是能找到问题所在的。