如何在 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);
}
这种方法的缺点是它将一些逻辑卸载到 View 并使 View 更复杂并且您的控制器更难测试:
来自项目的递归列表
<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);
}
这种方法的缺点是它将一些逻辑卸载到 View 并使 View 更复杂并且您的控制器更难测试: