我希望在Web应用程序中以树形结构显示数据。我希望使用Angular完成这个任务。
看起来ng-repeat将允许我遍历节点列表,但是当给定节点的深度增加时,如何进行嵌套呢?
我尝试了以下代码,但HTML的自动转义导致它无法正常工作。此外,结束ul标签的位置也不正确。
我很确定自己完全错误地处理了这个问题。
有什么想法吗?
看看这个fiddle
原始链接:http://jsfiddle.net/brendanowen/uXbn6/8/
更新后的链接:http://jsfiddle.net/animaxf/uXbn6/4779/
这将让你了解如何使用angular显示类似树形的结构。它在html中使用递归的方式实现!
module.factory('RecursionHelper', ['$compile', function($compile){
return {
/**
* Manually compiles the element, fixing the recursion loop.
* @param element
* @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
* @returns An object containing the linking functions.
*/
compile: function(element, link){
// Normalize the link parameter
if(angular.isFunction(link)){
link = { post: link };
}
// Break the recursion loop by removing the contents
var contents = element.contents().remove();
var compiledContents;
return {
pre: (link && link.pre) ? link.pre : null,
/**
* Compiles and re-adds the contents
*/
post: function(scope, element){
// Compile the contents
if(!compiledContents){
compiledContents = $compile(contents);
}
// Re-add the compiled contents to the element
compiledContents(scope, function(clone){
element.append(clone);
});
// Call the post-linking function, if any
if(link && link.post){
link.post.apply(null, arguments);
}
}
};
}
};
}]);
通过该服务,您可以轻松地创建一个树形指令(或其他递归指令)。以下是树形指令的示例:
module.directive("tree", function(RecursionHelper) {
return {
restrict: "E",
scope: {family: '='},
template:
'<p>{{ family.name }}</p>'+
'<ul>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child"></tree>' +
'</li>' +
'</ul>',
compile: function(element) {
return RecursionHelper.compile(element);
}
};
});
请查看Plunker以获取演示。
更新:添加了对自定义链接函数的支持。
这里有一个使用递归指令的示例:http://jsfiddle.net/n8dPm/ 引自https://groups.google.com/forum/#!topic/angular/vswXTes_FtM
module.directive("tree", function($compile) {
return {
restrict: "E",
scope: {family: '='},
template:
'<p>{{ family.name }}</p>'+
'<ul>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child"></tree>' +
'</li>' +
'</ul>',
compile: function(tElement, tAttr) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
<ul dx-start-with="rootNode">
<li ng-repeat="node in $dxPrior.nodes">
{{ node.name }}
<ul dx-connect="node"/>
</li>
</ul>
对我而言,这比为不同结构的树创建多个指令更加清晰。实质上,将上述内容称为树有些不准确,它更多地借鉴了@ ganaraj的“递归模板”,但允许我们在需要树的位置定义模板。
(您可以使用基于脚本标记的模板来实现,但它仍然必须位于实际树节点的右侧,并且仍然感觉有点糟糕...)
这里只是另一个选择...
<script type="text/ng-template" id="tree_item_renderer.html"></script>
<ul ng-app="Application" style="list-style-type: none; padding-left: 0">
<tree data='{name: "Node", nodes: [],show:true}'></tree>
</ul>
angular.module("myApp",[]);
/* https://dev59.com/uWYq5IYBdhLWcg3wfwxx#14657310 */
angular.module("myApp").
directive("recursive", function($compile) {
return {
restrict: "EACM",
require: '^tree',
priority: 100000,
compile: function(tElement, tAttr) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents);
}
compiledContents(scope,
function(clone) {
iElement.append(clone);
});
};
}
};
});
angular.module("myApp").
directive("subTree", function($timeout) {
return {
restrict: 'EA',
require: '^tree',
templateUrl: 'tree_item_renderer.html',
scope: {
data: '=',
},
link: function(scope, element, attrs, treeCtrl) {
scope.select = function(){
treeCtrl.select(scope.data);
};
scope.delete = function() {
scope.data.parent.nodes.splice(scope.data.parent.nodes.indexOf(scope.data), 1);
};
scope.add = function() {
var post = scope.data.nodes.length + 1;
var newName = scope.data.name + '-' + post;
scope.data.nodes.push({name: newName,nodes: [],show:true, parent: scope.data});
};
scope.edit = function(event){
scope.data.editting = true;
$timeout(function(){event.target.parentNode.querySelector('input').focus();});
};
scope.unedit = function(){
scope.data.editting = false;
};
}
};
});
angular.module("myApp").
directive("tree", function(){
return {
restrict: 'EA',
template: '<sub-tree data="data" root="data"></sub-tree>',
controller: function($scope){
this.select = function(data){
if($scope.selected){
$scope.selected.selected = false;
}
data.selected = true;
$scope.selected = data;
};
},
scope: {
data: '=',
}
}
});