Ng-повторить один элемент над вложенными объектами
Скажем, у меня есть объект с ключами, соответствующими продуктам и значениям, соответствующим объектам, которые, в свою очередь, имеют ключи, соответствующие ценовым точкам, в которых продавались эти продукты, и значения, соответствующие проданной сумме.
Например, если я продал 10 виджетах по 1 и 5 виджетам по цене $2, у меня была бы структура данных:
{ 'widget': {'1': 10, '2': 5} }
Я бы хотел обработать эту структуру и создать строки в таблице, например:
thing price amount
---------------------
widget $1 10
widget $2 5
В Python можно вставлять списки, чтобы отслеживать структуры данных списков, подобные этому. Возможно ли такое, используя ng-repeat?
Ответы
Ответ 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);
}
};
}]);