Ng-повторить один элемент над вложенными объектами - программирование
Подтвердить что ты не робот

Ng-повторить один элемент над вложенными объектами

Скажем, у меня есть объект с ключами, соответствующими продуктам и значениям, соответствующим объектам, которые, в свою очередь, имеют ключи, соответствующие ценовым точкам, в которых продавались эти продукты, и значения, соответствующие проданной сумме.

Например, если я продал 10 виджетах по 1 и 5 виджетам по цене $2, у меня была бы структура данных:

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

Я бы хотел обработать эту структуру и создать строки в таблице, например:

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

В Python можно вставлять списки, чтобы отслеживать структуры данных списков, подобные этому. Возможно ли такое, используя ng-repeat?

4b9b3361

Ответ 1

ng-repeat в настоящее время не имеет возможности скомпоновать итерацию внутри объектов (как это возможно в python). Проверьте исходный код ng-repeat и обратите внимание, что соответствие выражения регулярного выражения:

(key, value) in collection - и что они нажимают на массив ключей и присваивают список значений, и поэтому вы не можете иметь сложный ng-repeat грустно...

В основном есть два типа решений, на которые уже были приведены ответы:

  • Вложенный ng-repeat, как и первый ответ.
  • Восстановление вашего объекта данных в соответствии с 1 ng-repeat, как и второй ответ.

Я думаю, что решение 2 лучше, так как мне нравится сохранять логику сортировки и кодирования внутри контроллера, а не обрабатывать его в документе HTML. Это также позволит более сложную сортировку (в зависимости от цены, количества, имени widgetName или некоторой другой логики).

Другое дело - второе решение будет перебирать возможные методы набора данных (поскольку hasOwnProperty там не использовался).

Я улучшил решение в этом Plunker (на основе finalmove 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

Как насчет этого?

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 хотя)

Ответ 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);

        }
    };
}]);