代码之家  ›  专栏  ›  技术社区  ›  fadedbee

如何在没有html元素的情况下使用ng repeat

  •  148
  • fadedbee  · 技术社区  · 14 年前

    我需要使用 ng-repeat (在AngularJS中)列出数组中的所有元素。

    复杂的是,数组的每个元素都将转换为表的一行、两行或三行。

    我无法创建有效的html,如果 ng重复 在元素上使用,因为在 <tbody> <tr>

    例如,如果我在 <span> ,我会得到:

    <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>          
    
    8 回复  |  直到 14 年前
        1
  •  71
  •   Community Mohan Dere    9 年前

    从AngularJS 1.2开始,有一个指令叫做 ng-repeat-start 这正是你所要求的。看看我的答案 in this question 有关如何使用它的说明。

        2
  •  68
  •   Mark Rajcok    12 年前

    更新: 如果使用Angular 1.2+,请使用 ng-repeat-start 。参见@jmagnusson的回答。

    否则,把ng重复放在tbody上怎么样?(AFAIK,在一个表中有多个<tbody>是可以的。)

    <tbody ng-repeat="row in array">
      <tr ng-repeat="item in row">
         <td>{{item}}</td>
      </tr>
    </tbody>
    
        3
  •  39
  •   Duka Árpád    11 年前

    如果使用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>

    重要的一点:对于用于 ng-repeat-start ng-repeat-end 设置 ng-if="0" ,不允许插入到页面中。通过这种方式,内部内容将完全按照knockoutjs中的方式进行处理(使用中的命令 <!--...--> ),就不会有垃圾了。

        4
  •  20
  •   btford    14 年前

    您可能希望将控制器中的数据展平:

    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>
    
        5
  •  10
  •   agelbess    11 年前

    以上是正确的,但对于更一般的答案来说,这是不够的。我需要嵌套ng repeat,但保持在相同的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>
    

    注意ng if=“false”隐藏了起始和结束div。

    它应该打印

    名称1,名称1_1,名称1,2,名称2,名称2_1,名称2_2,

        6
  •  1
  •   Ar Es    10 年前

    我只想发表评论,但我的声誉仍然很差。所以我添加了另一个解决方案,它也解决了这个问题。我真的很想反驳@bmoeskau的说法,即解决这个问题最多需要一个“巧妙”的解决方案,由于这是最近在一次讨论中出现的,尽管这篇文章已经发布了2年,但我想加上我自己的两分钱:

    正如@btford所指出的,您似乎试图将递归结构转换为列表,因此应该首先将该结构扁平化为列表。他的解决方案做到了这一点,但有一种观点认为,在模板内调用函数是不雅的。如果这是真的(老实说,我不知道),那难道不需要执行控制器中的函数而不是指令吗?

    无论哪种方式,html都需要一个列表,因此呈现它的作用域应该使用该列表。您只需将控制器内部的结构压平即可。一旦有了$scope.rows数组,就可以用一个简单的ng repeat生成表。没有黑客,没有不雅,只是它的设计工作方式。

    Angulars指令并不缺乏功能。它们只是强迫您编写有效的html。我的一位同事也有类似的问题,他引用@bmoeskau来支持对angulars模板/渲染功能的批评。当研究确切的问题时,事实证明他只是想生成一个打开的标签,然后在其他地方生成一个关闭的标签,等等。就像过去我们从字符串中连接html一样。。正确的不

    至于将结构扁平化为列表,这里有另一个解决方案:

    // 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']
    

    这将适用于任何具有子项的树状结构。如果你想要整个项目而不是一个属性,你可以进一步缩短扁平化函数。

    希望这会有所帮助。

        7
  •  0
  •   Clint    7 年前

    一个真正有效的解决方案

    html格式

    <remove  ng-repeat-start="itemGroup in Groups" ></remove>
       html stuff in here including inner repeating loops if you want
    <remove  ng-repeat-end></remove>
    

    添加angular.js指令

    //remove directive
    (function(){
        var remove = function(){
    
            return {    
                restrict: "E",
                replace: true,
                link: function(scope, element, attrs, controller){
                    element.replaceWith('<!--removed element-->');
                }
            };
    
        };
        var module = angular.module("app" );
        module.directive('remove', [remove]);
    }());
    

    为了简单说明,

    ng重复序列自身与 <remove> 元素和循环,因为我们使用了ng repeat start/ng repeat end,所以它循环一个html块,而不仅仅是一个元素。

    然后自定义remove指令将 <删除> 起点和终点元素 <!--removed element-->

        8
  •  -2
  •   Renan Tomal Fernandes    14 年前
    <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>
    

    我认为这是有效的:)