在Angular中使用ng-repeat进行递归

Pro*_*ofK 19 javascript recursion angularjs angularjs-ng-repeat

我在sidemenu中的项目中有以下数据结构,基于付费网站主题的Angular应用程序.数据结构是我自己的,菜单来自原始菜单视图,所有项目都是ul硬编码的.

SidebarController.js:

$scope.menuItems = [
    {
        "isNavItem": true,
        "href": "#/dashboard.html",
        "text": "Dashboard"
    },
    {
        "isNavItem": true,
        "href": "javascript:;",
        "text": "AngularJS Features",
        "subItems": [
            {
                "href": "#/ui_bootstrap.html",
                "text": " UI Bootstrap"
            },
            ...
        ]
    },
    {
        "isNavItem": true,
        "href": "javascript:;",
        "text": "jQuery Plugins",
        "subItems": [
            {
                "href": "#/form-tools",
                "text": " Form Tools"
            },
            {
                "isNavItem": true,
                "href": "javascript:;",
                "text": " Datatables",
                "subItems": [
                    {
                        "href": "#/datatables/managed.html",
                        "text": " Managed Datatables"
                    },
                    ...
                ]
            }
        ]
    }
];
Run Code Online (Sandbox Code Playgroud)

然后我将以下部分视图绑定到该模型,如下所示:

<ul class="page-sidebar-menu" data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200" ng-class="{'page-sidebar-menu-closed': settings.layout.pageSidebarClosed}">
    <li ng-repeat="item in menuItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}">
        <a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
            <span class="title">{{item.text}}</span>
        </a>
        <ul ng-if="item.subItems && item.subItems.length > 0" class="sub-menu">
            <li ng-repeat="item in item.subItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}">
                <a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
                    <span class="title">{{item.text}}</span>
                </a>
            </li>
        </ul>
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

注意$scope视图绑定中可能存在您未在模型中看到的属性,反之亦然,但这是因为我为了简洁而编辑了它们.现在因为第二级li也没有包含ul自己的条件,subItems所以Datatable菜单项下的子项不会被渲染.

如何创建将递归绑定到模型的视图或模板,或两者,以便呈现所有子项的所有子项?这通常只有四个级别.

Rah*_*ora 16

你可以简单地使用ng-include来制作一个部分并递归调用它:Partial应该是这样的:

<ul>
    <li ng-repeat="item in item.subItems">
      <a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
          <span class="title">{{item.text}}</span>
      </a>
      <div ng-switch on="item.subItems.length > 0">
        <div ng-switch-when="true">
          <div ng-init="subItems = item.subItems;" ng-include="'partialSubItems.html'"></div>  
        </div>
      </div>
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

而你的HTML:

<ul class="page-sidebar-menu" data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200" ng-class="{'page-sidebar-menu-closed': settings.layout.pageSidebarClosed}">
    <li ng-repeat="item in menuItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}">
        <a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
            <span class="title">{{item.text}}</span>
        </a>
        <ul ng-if="item.subItems && item.subItems.length > 0" class="sub-menu">

            <li ng-repeat="item in item.subItems" ng-class="{'start': item.isStart, 'nav-item': item.isNavItem}">
                 <a href="{{item.href}}" ng-class="{'nav-link nav-toggle': item.subItems && item.subItems.length > 0}">
                    <span class="title">{{item.text}}</span>
                </a>

                 <div ng-switch on="item.subItems.length > 0">
                    <div ng-switch-when="true">
                      <div ng-init="subItems = item.subItems;" ng-include="'newpartial.html'"></div>  
                    </div>
                </div>

            </li>
        </ul>
    </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

这是工作的plunker http://plnkr.co/edit/9HJZzV4cgacK92xxQOr0?p=preview


Sha*_*Roy 10

您可以通过包含javascript模板 和使用ng-include的模板来实现此目的

定义javascript模板

<script type="text/ng-template" id="menu.html">...</script>
Run Code Online (Sandbox Code Playgroud)

并包括它:

<div ng-if="item.subItems.length" ng-include="'menu.html'"></div>
Run Code Online (Sandbox Code Playgroud)

示例:在此示例中,我使用了基本的html而没有任何类,您可以根据需要使用类.我刚刚展示了基本的递归结构.

html中:

<ul>
    <li ng-repeat="item in menuItems">
      <a href="{{item.href}}">
        <span>{{item.text}}</span>
      </a>
      <div ng-if="item.subItems.length" ng-include="'menu.html'"></div>
    </li>
</ul>


<script type="text/ng-template" id="menu.html">
   <ul>
      <li ng-repeat="item in item.subItems">
        <a href="{{item.href}}">
          <span>{{item.text}}</span>
        </a>
        <div ng-if="item.subItems.length" ng-include="'menu.html'"></div>
      </li>
   </ul>
</script>
Run Code Online (Sandbox Code Playgroud)

PLUNKER DEMO


Jos*_*cha 7

如果你的目的是绘制一个具有无限级子项的菜单,那么一个好的实现就是制定一个指令.

使用指令,您将能够更好地控制菜单.

我创建了一个带有完全递归的基本exepmle,你可以看到在同一页面上轻松实现多个菜单,在其中一个菜单上看到超过3个级别,请参阅此plunker.

码:

.directive('myMenu', ['$parse', function($parse) {
    return {
      restrict: 'A',
      scope: true,
      template:
        '<li ng-repeat="item in List" ' +
        'ng-class="{\'start\': item.isStart, \'nav-item\': item.isNavItem}">' +
        '<a href="{{item.href}}" ng-class="{\'nav-link nav-toggle\': item.subItems && item.subItems.length > 0}">'+
        '<span class="title"> {{item.text}}</span> ' +
        '</a>'+
        '<ul my-menu="item.subItems" class="sub-menu"> </ul>' +
        '</li>',
      link: function(scope,element,attrs){
        //this List will be scope invariant so if you do multiple directive 
        //menus all of them wil now what list to use
        scope.List = $parse(attrs.myMenu)(scope);
      }
    }
}])
Run Code Online (Sandbox Code Playgroud)

标记:

<ul class="page-sidebar-menu" 
    data-keep-expanded="false" 
    data-auto-scroll="true" 
    data-slide-speed="200" 
    ng-class="{'page-sidebar-menu-closed': settings.layout.pageSidebarClosed}"
    my-menu="menuItems">
</ul>
Run Code Online (Sandbox Code Playgroud)

编辑

一些笔记

在做出决定时ng-include(我认为这是一个公平的解决方案)或者.directive,你必须首先问自己至少两个问题.我的代码片段是否需要一些逻辑?如果没有,你也可以去ng-include.但是如果你要在片段中放入更多的逻辑使其可自定义,对元素或attrs(DOM)操作进行更改,你应该去指令.还有一点让我对这个指令变得更加舒适,那就是你编写的代码的可重用性,因为在我的例子中你可以给出更多的控制权并制作一个更通用的代码我认为如果你的项目很大且需要你应该去做成长.所以第二个问题是我的代码可以重用吗?

一种用于清洁指令提醒的是,而不是template您可以使用templateUrl,你可以给一个文件喂HTML代码,目前在template.

如果您使用1.5+,您现在可以选择使用.component.Component是一个包装器arroud .direcitve,其样板代码少得多.在这里你可以看到差异.

                  Directive                Component

bindings          No                       Yes (binds to controller)
bindToController  Yes (default: false)     No (use bindings instead)
compile function  Yes                      No
controller        Yes                      Yes (default function() {})
controllerAs      Yes (default: false)     Yes (default: $ctrl)
link functions    Yes                      No
multiElement      Yes                      No
priority          Yes                      No
require           Yes                      Yes
restrict          Yes                      No (restricted to elements only)
scope             Yes (default: false)     No (scope is always isolate)
template          Yes                      Yes, injectable
templateNamespace Yes                      No
templateUrl       Yes                      Yes, injectable
terminal          Yes                      No
transclude        Yes (default: false)     Yes (default: false)
Run Code Online (Sandbox Code Playgroud)

组件的源角度指南

编辑

正如Mathew Berg所说,如果你想不包含ul元素,如果subItems列表为空,你可以将ul更改为这样的东西 <ul ng-if="item.subItems.length>0" my-menu="item.subItems" class="sub-menu"> </ul>