且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在 ng-repeat 中循环遍历深层对象

更新时间:2023-10-26 14:11:34

给你:

html

<ul><linested-item ng-repeat="item in items">{{item.title}}</li>

JavaScript

var items = [{title: '东西',孩子们: [{ 标题:'你好世界' },{ title: '你好溢出' },{ 标题:'John Doe',孩子们:[{ title: '惊人的标题' },{ title: '谷歌它' },{标题:'我是一个孩子',孩子们:[{ title: '另一个' },{ title: '他是我的兄弟' },{标题:'她是我的妈妈.',孩子们:[{title: '你永远不知道我是否会生孩子'}]}]}]}]}];var app = angular.module('app', []);app.controller('test', function( $scope ) {$scope.items = 物品;});app.directive('nestedItem', ['$compile', function($compile){返回 {限制:'A',链接:功能(范围,元素){控制台日志(元素);如果(范围.item.children){var html = $compile('<ul><li nested-item ng-repeat="item.children 中的项目">{{item.title}}</li></ul>')(范围);element.append(html);}}};}]);

我分叉了你的小提琴:

http://jsfiddle.net/c4Kp8/

实际上,我必须承认我喜欢 Master Morality 的方法,但您也可以使用自定义指令.如果你走那条路线,要知道的关键是你需要在项目级别进行拦截以手动检查当前项目是否有子项,如果有,自己为节点编译指令.

更新

然而,在上面的代码中有一件事情应该困扰我们.html 代码的重复(在指令中内联)是一种代码异味.如果你愿意,你可以变得非常时髦并通过引入一个通用的 template-code 指令来解决这个问题,该指令不做任何其他事情,但提供应用它的节点的代码作为模板其他指令.

那么我们的解决方案将如下所示:

html

<ul模板代码><linested-item ng-repeat="item in items">{{item.title}}</li>

JavaScript

var items = [{title: '东西',孩子们: [{ 标题:'你好世界' },{ title: '你好溢出' },{ 标题:'John Doe',孩子们:[{ title: '惊人的标题' },{ title: '谷歌它' },{标题:'我是一个孩子',孩子们:[{ title: '另一个' },{ title: '他是我的兄弟' },{标题:'她是我的妈妈.',孩子们:[{title: '你永远不知道我是否会生孩子'}]}]}]}]}];var app = angular.module('app', []);app.controller('test', function( $scope ) {$scope.items = 物品;});app.directive('templateCode', function(){返回 {限制:'A',控制器:函数(){},编译:函数(元素){element.removeAttr('模板代码');//注意:我们需要在这里修剪().否则 AngularJS 会引发异常//稍后当我们想在 $compile 函数中使用模板代码时.//请注意,我们假设一个现代浏览器//已经带有修剪功能.//使用 polyfill 很容易确保它的安全.var templateCode = element.parent().html().trim();返回函数(范围,iElement,iAttrs,控制器){控制器模板代码 = 模板代码;}}}});app.directive('nestedItem', ['$compile', function($compile){返回 {限制:'A',要求:'^模板代码',链接:功能(范围,元素,iAttr,控制器){如果(范围.item.children){scope.items = scope.item.children;var html = $compile(controller.templateCode)(scope);element.append(html);}}};}]);

Plunker:http://jsfiddle.net/2rQWf/

I'm in angular and i have a object like this.

var items = [{
    title: 'Something',
    children: [
        { title: 'Hello World' },
        { title: 'Hello Overflow' },
        { title: 'John Doe', children: [
            { title: 'Amazing title' },
            { title: 'Google it' },
            { title: 'I'm a child', children: [
                { title: 'Another ' },
                { title: 'He\'s my brother' },
                { title: 'She\'s my mother.', children: [
                    {title: 'You never know if I'm going to have children'}
                ]}
            ]}
        ]}
    ]
}];

I wan't to loop through all of these so i have something like this.

    • Something

       • Hello World

       • Hello Overflow

       • John Doe

          • Amazing Title

          • Google it

          • I'm a child

              • Another

              • He's my brother

              • She's my mother

                  • You never know if I'm going to have children

The problem is I wouldn't know how deep this object will go or what's in it. so I wouldn't be able to do it manually. I have done a basic loop with ng-repeat in the fiddle provided at the bottom, but i can't figure out how I can automatically loop through these and create nested <ul>'s and <li>'s.

What would be the best way to accomplish this?

Demo: http://jsfiddle.net/XtgLM/

Here you go:

html

<div ng-app="app" ng-controller="test">
   <ul>
       <li nested-item ng-repeat="item in items">{{item.title}}</li>
   </ul>         
</div>

JavaScript

var items = [{
    title: 'Something',
    children: [
        { title: 'Hello World' },
        { title: 'Hello Overflow' },
        { title: 'John Doe', children: [
            { title: 'Amazing title' },
            { title: 'Google it' },
            { title: 'Im a child', children: [
                { title: 'Another ' },
                { title: 'He\'s my brother' },
                { title: 'She\'s my mother.', children: [
                    {title: 'You never know if im going to have children'}
                ]}
            ]}
        ]}
    ]
}];

var app = angular.module('app', []);

app.controller('test', function( $scope ) {
    $scope.items = items;
});


app.directive('nestedItem', ['$compile', function($compile){
    return {
        restrict: 'A',
        link: function(scope, element){
        console.log(element);
            if (scope.item.children){
                var html = $compile('<ul><li nested-item ng-repeat="item in item.children">{{item.title}}</li></ul>')(scope);
                element.append(html);
            }
        }
    };
}]);

I forked your fiddle:

http://jsfiddle.net/c4Kp8/

Actually I must confess that I like Master Morality's approach but you can also go with a custom directive. The key thing to know if you go that route is that you need to intercept on the item level to manually check if the current item has children, and if so, $compile the directive for the node yourself.

UPDATE

However, there is one thing that should bother us in the above code. The duplication of html code (inlined in the directive) is a code smell. If you like, you can get really funky and fix this by introducing a generic template-code directive which doesn't do anything else but providing the code of the node where it is applied on as a template for other directives.

So then our solution would look like this:

html

<div ng-app="app" ng-controller="test">
   <ul template-code>
       <li nested-item ng-repeat="item in items">{{item.title}}</li>
   </ul>         
</div>

JavaScript

var items = [{
    title: 'Something',
    children: [
        { title: 'Hello World' },
        { title: 'Hello Overflow' },
        { title: 'John Doe', children: [
            { title: 'Amazing title' },
            { title: 'Google it' },
            { title: 'Im a child', children: [
                { title: 'Another ' },
                { title: 'He\'s my brother' },
                { title: 'She\'s my mother.', children: [
                    {title: 'You never know if im going to have children'}
                ]}
            ]}
        ]}
    ]
}];

var app = angular.module('app', []);

app.controller('test', function( $scope ) {
    $scope.items = items;
});

app.directive('templateCode', function(){
    return {
        restrict: 'A',
        controller: function(){},
        compile: function(element){
            element.removeAttr('template-code');
            //ATTENTION: We need to trim() here. Otherwise AngularJS raises an exception
            //later when we want to use the templateCode in a $compile function. 
            //Be aware that we assume a modern browser 
            //that already ships with a trim function.
            //It's easy to secure that with a polyfill.
            var templateCode = element.parent().html().trim();
            return function(scope, iElement, iAttrs, controller){
                controller.templateCode = templateCode;
            }
        }
    }
});

app.directive('nestedItem', ['$compile', function($compile){
    return {
        restrict: 'A',
        require: '^templateCode',
        link: function(scope, element, iAttr, controller){ 
            if (scope.item.children){
                scope.items = scope.item.children;         
                var html = $compile(controller.templateCode)(scope);
                element.append(html);
            }
        }
    };
}]);

Plunker: http://jsfiddle.net/2rQWf/