如何在 angularjs 中为递归模板创建行选择器

How to create row selector for recursive template in angularjs

来自项目的递归列表

<script type="text/ng-template" id="menu_sublevel.html">
    id:{{item.id}}
    <ul ng-if="item.subs">
        <li ng-repeat="item in item.subs" ng-click="openItem(item)" ng-include="'menu_sublevel.html'">
            id:{{item.id}}
        </li>
    </ul>
</script>

<ul>
    <li ng-repeat="item in menu.items" ng-click="$event.stopPropagation()" ng-include="'menu_sublevel.html'"></li>
</ul>

效果

 id:0
    ...id:4
    ...id:5
       ...id:16
       ...id:17
       ...id:18
    ...id:6
       ...id:20
       ...id:21
       ...id:22

我想 select 一次买一件。 当我在没有递归的情况下编写嵌套列表时,我使用 id 并且在每个级别上我都有项目 selection 的方法并且我 chceck `

levelOneItemSelected.id === item.id

如何 select child with id 16 并打开他的 parent with id 5 和下一个 parent with id 0 打开同时更改 select ion 关闭打开的项目。

如果在调用 openItem(item) 时,您还想 select/open 它的祖先,那么最好从 item 到它的父级的引用,例如 item.$$parent。这将使您能够遍历 item 的祖先并修改它们。从概念上讲,它看起来像这样:

$scope.openItem(item){
  item.isOpen = true;
  while (item.$$parent){
    item = item.$$parent;
    item.isOpen = true;
  }
}

因此,一种方法是预处理您的项目并相应地设置 .$$parent 属性。

如果您不喜欢更改 item 对象(可能是您的域模型)的想法,您始终可以预处理域模型并生成包含域模型的视图模型。它看起来像这样(在概念上):

$scope.menu = [
  { $$parent: null,
    item: {id: 0, subs: [
      { $$parent: parentObj, // points to its parent
        item: {id: 10, subs: [...]}
      }
    ]}
  },
  // etc ...
]

但是如果您不想修改任何一个,您可以使用 ng-repeat 创建子范围并在每个范围级别实例化 $$ancestors 属性 的事实。 (另请注意,ng-click 应该在显示的项目上,而不是在子项目的 <li> 上):

<script type="text/ng-template" id="menu_sublevel.html">
    <span ng-click="openItem(item, $$ancestors)"
          ng-class="{'open': item.isOpen}">id:{{item.id}}</span>

    <ul ng-if="item.subs" 
        ng-init="$$p = $$ancestors.slice(); $$p.push(item)">

        <li ng-repeat="item in item.subs" 
            ng-init="$$ancestors = $$p"
            ng-include="'menu_sublevel.html'">
            id:{{item.id}}
        </li>
    </ul>
</script>

<ul>
    <li ng-repeat="item in menu.items" 
        ng-init="$$ancestors = []"
        ng-include="'menu_sublevel.html'"></li>
</ul>

然后,在controller中,openItem需要改成:

var currentOpenItem = null,
    currentOpenItemAncestors = [];

$scope.openItem = function(item, ancestors){
   // closes the currently open item and its ancestors
   closeItem(currentOpenItem, currentOpenItemAncestors);

   currentOpenItem = item;
   currentOpenItemAncestors = ancestors;

   openItem(item, ancestors);
}

Demo

这种方法的缺点是它将一些逻辑卸载到 View 并使 View 更复杂并且您的控制器更难测试: