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

时间:2015-08-10 08:43:08

标签: javascript angularjs recursion angularjs-ng-repeat nested-lists

来自递归的项目清单

<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

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

  

levelOneItemSelected.id === item.id

如何选择ID为16且启用了ID为5的父级,并且在更改选择时打开了ID为0的下一位父级关闭了已打开的项目。

1 个答案:

答案 0 :(得分:1)

如果在调用openItem(item)时,您还想选择/打开其祖先,那么最好将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>

然后,在控制器中,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更加复杂,并且您的控制器不易测试: