【问题标题】:ng-repeat a single element over nested objectsng-在嵌套对象上重复单个元素
【发布时间】:2017-07-04 07:14:15
【问题描述】:

假设我有一个对象,其键对应于产品,值对应于对象,而对象的键对应于这些产品已售出的价格点,值对应于销售量。

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

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

我想循环这个结构并在一个表中生成行:

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

在 Python 中,可以嵌套列表推导来遍历像这样的列表数据结构。使用 ng-repeat 可以实现这样的事情吗?

【问题讨论】:

  • 只针对搜索引擎,我会为c#背景的程序员添加,“在angularjs中如何做SelectMany”

标签: angularjs angularjs-ng-repeat


【解决方案1】:

这个怎么样?

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$first$middle$last)并使用ng-class(甚至原生CSS 选择器,例如:last-child -- 我会推荐ng-class

【讨论】:

  • 我会使用多个 tbody 而不是多个表
  • 这绝对是我正在寻找的东西,但恐怕使用单独的表/tbodies 并不是一个真正的选择。如果可以神奇地在元素上重复一个属性,那将是理想的。
  • 哦,如果你的意思是“神奇地”将 outer 重复推到地毯下,那是不可能的,我担心......你介意详细说明一下限制吗tbody 是?
【解决方案2】:

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

(key, value) in collection - 他们推入键数组并分配给值列表,所以你不可能有一个复杂的 ng-repeat 遗憾...

这里基本上已经回答了 2 种类型的解决方案

  1. 嵌套 ng-repeat 就像建议的第一个答案一样。
  2. 按照建议的第二个答案重新构建您的数据对象以适应 1 ng-repeat。

我认为解决方案 2 更好,因为我喜欢将排序和编码逻辑保留在控制器中,而不是在 HTML 文档中处理它。这也将允许更复杂的排序(即基于价格、金额、widgetName 或其他一些逻辑)。

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

我已经改进了这个 Plunker 中的解决方案(基于finishmove 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>

【讨论】:

    【解决方案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/

    【讨论】:

    • 这当然是一种选择,但我不希望仅仅为了显示它而重新构建数据结构。不过,如果没有人提出更好的答案,我会接受你的答案。
    【解决方案4】:

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

    代码:

    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);
    
            }
        };
    }]);

    我的对象:

    $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"
                      }]
                  }
              ]
          }
      ];

    我的 HTML

    &lt;nested-items&gt;&lt;/nested-items&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 2016-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多