在嵌套对象上重复单个元素

时间:2013-08-20 08:33:09

标签: angularjs angularjs-ng-repeat

假设我有一个对象,其中的键对应于与对象相对应的产品和值,而对象又具有与这些产品已售出的价格点相对应的键,以及与销售量相对应的值。

例如,如果我以1美元的价格出售10个小部件,以2美元的价格出售5个小部件,我将拥有数据结构:

{ 'widget': {'1': 10, '2': 5} }

我想循环这个结构并在表格中生成行,例如:

thing   price  amount
---------------------
widget  $1     10
widget  $2     5

在Python中,可以将列表推导嵌套到遍历列表这样的数据结构。使用ng-repeat会这样吗?

4 个答案:

答案 0 :(得分:18)

这个怎么样?

http://plnkr.co/edit/ZFgu8Q?p=preview

控制器:

$scope.data = {
  'widget1': {
    '1': 10,
    '2': 5
  },
  'widget2': {
    '4': 7,
    '6': 6
  }
};

查看:

<div ng-controller="MyCtrl">
    <table>
      <thead>
        <tr>
          <td>thing</td>
          <td>price</td>
          <td>amount</td>
        </tr>
      </thead>
      <tbody ng-repeat="(productName, productData) in data">
        <tr ng-repeat="(price, count) in productData">
            <td>{{productName}}</td>
            <td>{{price|currency}}</td>
            <td>{{count}}</td>
        </tr>
      </tbody>
    </table>
</div>

输出:

thing   price   amount
----------------------
widget1 $1.00   10
widget1 $2.00   5
widget2 $4.00   7
widget2 $6.00   6

这将为每个产品输出tbody(感谢Sebastien C的好主意)。 如果需要,您可以区分第一个,中间和最后一个tbody(使用ng-repeat的{​​{1}},$first$middle)并将其设置为{ {1}}(甚至是$last等原生CSS选择器 - 我建议使用ng-class

答案 1 :(得分:13)

ng-repeat目前没有一种可能的方法来复制对象内部的迭代(在python中可能的方式)。查看ng-repeat source code并注意匹配的正则表达式是:

(key, value) in collection - 并且他们会进入密钥数组并分配给值列表,因此您不可能遗憾地拥有复杂的ng-repeat ...

基本上有两种类型的解决方案已经回答

  1. 嵌套的ng-repeat,如第一个答案所示。
  2. 重建您的数据对象以适应1 ng-repeat,如建议的第二个答案。
  3. 我认为解决方案2更好,因为我喜欢保持我的排序和放大控制器内部的编码逻辑,而不是在HTML文档中处理它。这也将允许更复杂的排序(即基于价格,金额,widgetName或其他一些逻辑)。

    另一件事 - 第二个解决方案将迭代数据集的可能方法(因为那里没有使用 hasOwnProperty )。

    我已经改进了 Plunker (基于最后的Plunker)的解决方案,以便使用angular.forEach并显示解决方案相当简单但允许复杂排序逻辑。

    $scope.buildData = function() {
    
      var returnArr = [];
    
      angular.forEach($scope.data, function(productData, widget) {
          angular.forEach(productData, function( amount, price) {
            returnArr.push( {widgetName: widget, price:price, amount:amount});            
          });
      });
       //apply sorting logic here
      return returnArr;
    };
    $scope.sortedData = $scope.buildData();
    

    然后在你的控制器中:

    <div ng-controller="MyCtrl">
        <table>
          <thead>
            <tr>
              <td>thing</td>
              <td>price</td>
              <td>amount</td>
            </tr>
          </thead>
          <tbody>
          <tr ng-repeat="item in sortedData">
            <td>{{ item.widgetName }}</td>
            <td>{{ item.price|currency }}</td>
            <td>{{ item.amount }} </td>
            </tr>
          </tbody>
        </table>
    </div>
    

答案 2 :(得分:3)

只需将对象转换为数组......在JS中它非常简单。 类似的东西:

$scope.data = { 'widget': { '1': 10, '2': 5 } };

var tableData = [];
for (item in $scope.data) {
    var thing = item;
    for (subitem in $scope.data[thing]) {
        tableData.push({
            thing: thing,
            price: subitem,
            amount: $scope.data[thing][subitem]
        });
    }
}

我用这个例子创建了一个jsfiddle:http://jsfiddle.net/b7TYf/

答案 3 :(得分:1)

我使用了一个简单的指令,它有一个递归函数来遍历我的嵌套对象并创建嵌套元素。这样就可以保留嵌套的对象结构。

代码:

&#13;
&#13;
angular.module('nerd').directive('nestedItems', ['$rootScope', '$compile', function($rootScope, $compile) {
    return {
        restrict: 'E',
        scope: false,
        link: function(scope, element, attrs, fn) {

            scope.addElement = function(elem, objAr) {

                var ulElement = angular.element("<ul></ul>");

                if (objAr ==  undefined || objAr.length == 0) {
                    return [];
                }

                objAr.forEach(function(arrayItem) {
                    var newElement = angular.element("<li>"+arrayItem.val+"</li>");
                    ulElement.append(newElement);
                    scope.addElement(newElement,arrayItem.sub);
                });

                elem.append(ulElement);
            };
            
            scope.addElement(element,scope.elements);

        }
    };
}]);
&#13;
&#13;
&#13;

我的对象:

&#13;
&#13;
$scope.elements = [

      {
          id: 1,
          val: "First Level",
          sub: [

              {
                  id: 2,
                  val: "Second Level - Item 1"
              },
              {
                  id: 3,
                  val: "Second Level - Item 2",
                  sub: [{
                      id: 4,
                      val: "Third Level - Item 1"
                  }]
              }
          ]
      }
  ];
&#13;
&#13;
&#13;

我的HTML

&#13;
&#13;
<nested-items></nested-items>
&#13;
&#13;
&#13;