如何在不使用html元素的情况下使用ng-repeat
我需要使用ng-repeat
(在AngularJS中)列出数组中的所有元素。
复杂的是,数组的每个元素将转换为表的一个,两个或三个行。
如果在元素上使用ng-repeat
,我无法创build有效的html,因为在<tbody>
和<tr>
之间不允许重复元素的types。
例如,如果我在<span>
上使用ng-repeat,我会得到:
<table> <tbody> <span> <tr>...</tr> </span> <span> <tr>...</tr> <tr>...</tr> <tr>...</tr> </span> <span> <tr>...</tr> <tr>...</tr> </span> </tbody> </table>
哪个是无效的html。
但是我需要生成的是:
<table> <tbody> <tr>...</tr> <tr>...</tr> <tr>...</tr> <tr>...</tr> <tr>...</tr> <tr>...</tr> </tbody> </table>
其中第一行由第一个数组元素生成,下三个由第二个数组生成,第五个和第六个由最后一个数组元素生成。
我如何使用ng-repeat,使得在渲染过程中绑定的html元素“消失”了?
还是有另一种解决办法呢?
澄清:生成的结构应该如下所示。 每个数组元素可以在表格的1-3行之间生成。 理想情况下,答案应该支持每个数组元素的0-n行。
<table> <tbody> <!-- array element 0 --> <tr> <td>One row item</td> </tr> <!-- array element 1 --> <tr> <td>Three row item</td> </tr> <tr> <td>Some product details</td> </tr> <tr> <td>Customer ratings</td> </tr> <!-- array element 2 --> <tr> <td>Two row item</td> </tr> <tr> <td>Full description</td> </tr> </tbody> </table>
更新:如果您使用的是Angular 1.2+,请使用ng-repeat-start 。 请参阅@ jmagnusson的答案。
否则,把ng-repeat放在tbody上怎么样? (AFAIK,可以在一个表中有多个<tbody>)。
<tbody ng-repeat="row in array"> <tr ng-repeat="item in row"> <td>{{item}}</td> </tr> </tbody>
从AngularJS 1.2 ng-repeat-start
,有一个叫做ng-repeat-start
的指令,完全符合你的要求。 请参阅我在这个问题上的答案,了解如何使用它的说明。
如果你使用ng> 1.2,下面是一个使用ng-repeat-start/end
而不产生不必要的标签的例子:
<html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <script> angular.module('mApp', []); </script> </head> <body ng-app="mApp"> <table border="1" width="100%"> <tr ng-if="0" ng-repeat-start="elem in [{k: 'A', v: ['a1','a2']}, {k: 'B', v: ['b1']}, {k: 'C', v: ['c1','c2','c3']}]"></tr> <tr> <td rowspan="{{elem.v.length}}">{{elem.k}}</td> <td>{{elem.v[0]}}</td> </tr> <tr ng-repeat="v in elem.v" ng-if="!$first"> <td>{{v}}</td> </tr> <tr ng-if="0" ng-repeat-end></tr> </table> </body> </html>
您可能希望将控制器中的数据平坦化:
function MyCtrl ($scope) { $scope.myData = [[1,2,3], [4,5,6], [7,8,9]]; $scope.flattened = function () { var flat = []; $scope.myData.forEach(function (item) { flat.concat(item); } return flat; } }
然后在HTML中:
<table> <tbody> <tr ng-repeat="item in flattened()"><td>{{item}}</td></tr> </tbody> </table>
以上是正确的,但对于更一般的答案是不够的。 我需要嵌套ng重复,但留在相同的html级别,这意味着将元素写入同一个父级。 标签数组包含也有标签数组的标签。 它实际上是一棵树。
[{ name:'name1', tags: [ { name: 'name1_1', tags: []}, { name: 'name1_2', tags: []} ]}, { name:'name2', tags: [ { name: 'name2_1', tags: []}, { name: 'name2_2', tags: []} ]} ]
所以这是我最终做的。
<div ng-repeat-start="tag1 in tags" ng-if="false"></div> {{tag1}}, <div ng-repeat-start="tag2 in tag1.tags" ng-if="false"></div> {{tag2}}, <div ng-repeat-end ng-if="false"></div> <div ng-repeat-end ng-if="false"></div>
注意隐藏开始和结束div的ng-if =“false”。
它应该打印
NAME1,name1_1,name1_2,NAME2 NAME2_1,name2_2,
我只想评论一下,但是我的声誉还是不足。 所以我添加了解决问题的另一个解决scheme。 我真的很想驳斥@bmoeskau所说的解决这个问题的声明,这个解决scheme需要一个“hacky最好”的解决scheme,而且由于这个问题最近出现在讨论中,即使这个post是2岁,我想添加我的拥有两分钱:
正如@btford所指出的那样,你似乎试图把一个recursion结构变成一个列表,所以你应该先把这个结构扁平化为一个列表。 他的解决scheme是这样做的,但有一种观点认为,调用模板内的函数是不够的。 如果这是真的(说实话,我不知道)不会只是需要执行控制器中的function,而不是指令?
无论哪种方式,你的HTML需要一个列表,所以呈现它的范围应该有该列表来处理。 你只需要扁平化你的控制器内部的结构。 一旦你有一个$ scope.rows数组,你可以用一个简单的ng-repeat生成表格。 没有黑客,没有不雅,只是它的devise工作方式。
Angulars指令并不缺乏function。 他们只是强迫你写有效的HTML。 我的同事也有类似的问题,引用@ bmoeskau来支持对angular色模板/渲染特性的批评。 当看到确切的问题时,事实certificate,他只是想生成一个开放标签,然后在其他地方的一个closures标签,就像在过去的好时代,我们将从string连接我们的HTML ..对吗? 没有。
至于把结构变成一个列表,下面是另一个解决scheme:
// assume the following structure var structure = [ { name: 'item1', subitems: [ { name: 'item2', subitems: [ ], } ], } ]; var flattened = structure.reduce((function(prop,resultprop){ var f = function(p,c,i,a){ p.push(c[resultprop]); if (c[prop] && c[prop].length > 0 ) p = c[prop].reduce(f,p); return p; } return f; })('subitems','name'),[]); // flattened now is a list: ['item1', 'item2']
这将适用于任何具有子项目的树状结构。 如果你想要整个项目而不是一个属性,你可以缩短更多的flatteningfunction。
希望有所帮助。
你可以使用下划线扁平化函数$scope.myData= _.flatten($scope.myData);
<table> <tbody> <tr><td>{{data[0].foo}}</td></tr> <tr ng-repeat="d in data[1]"><td>{{d.bar}}</td></tr> <tr ng-repeat="d in data[2]"><td>{{d.lol}}</td></tr> </tbody> </table>
我认为这是有效的:)