Как сортировать данные JSON в ng-repeat?
Я получаю ответ сервера и привязываю эти данные к просмотру с помощью ng-repeat. Теперь я хочу отсортировать эти данные на priceList
и name
. Я могу сортировать имя, используя orderBy
, но не с priceList
. Я хочу сортировать продукты на основе priceList
. Сортировка с именем изменяет порядок списка, а сортировка на priceList
будет производить только порядок products
для каждого category
. Он будет влиять на порядок отображаемой категории. Пожалуйста, помогите мне решить это.
Мой код:
<div ng-controller="Ctrl">
<pre>Sorting predicate = {{predicate}};</pre>
<hr/>
<table class="friend">
<tr>
<th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
</th>
<th><a href="" ng-click="predicate = 'priceList'>price</a></th>
</tr>
</table>
<div ng-repeat="data in _JSON[0].categories | orderBy:predicate">
<div ng-repeat="vals in data.itemTypeResults |orderBy:'partTerminologyName'" id="{{vals.partTerminologyName}}">
`<h4 style="background-color: gray">{{vals.partTerminologyName}} : Position :{{vals.position}}</h4>`<br>
<div ng-repeat="val in vals.products">
<b> Quantity:{{val[0].perCarQty}}</b><br>
<b> part:{{val[0].partNo}}</b><br>
<b>sku:{{val[0].sku}}</b><br>
<b> qtyInStock:{{val[0].qtyInStock}}</b><br>
<b> priceList:{{val[0].priceList}}</b><br>
<b>priceSave:{{val[0].priceSave}}</b><br>
<b> qtyDC:{{val[0].qtyDC}}</b><br>
<b> qtyNetwork:{{val[0].qtyNetwork}}</b><br>
<b> priceCore:{{val[0].priceCore}}</b><br>
</div>
</div>
</div>
JS:
$scope._JSON = [
{"categories":
[
{"id":14061,"name":"Drive Belts",
"itemTypeResults":[
{"partTerminologyName":"Serp. Belt",
"position":"Main Drive",
"products":{
"5060635":[
{"perCarQty":2,"partNo":"5060635",
"sku":"20060904","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":19.15,"priceSave":3.29,
"priceCore":10.0}
],
"635K6":[
{"perCarQty":9,"partNo":"635K6",
"sku":"10062449","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":18.15,"priceSave":3.21,"priceCore":10.0}
]
}
}
]
},
{"id":2610,"name":"Drive Belt Tensioners, Idlers, Pulleys & Components",
"itemTypeResults":[
{"partTerminologyName":"Drive Belt Tensioner Assembly",
"position":"N/A",
"products":{
"950489A":[
{"perCarQty":4,"partNo":"950489A",
"sku":"10150833","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":18.15,"priceSave":3.21,"priceCore":10.0
}
]
}},
{"partTerminologyName":"Drive Belt Idler Pulley","position":"N/A",
"products":{
"89161":[
{"perCarQty":1,"partNo":"89161",
"sku":"99995959","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":17.15,"priceSave":3.21,"priceCore":10.0}
],
"951373A":[
{"perCarQty":2,"partNo":"951373A","pla":"LTN",
"plaName":"Litens",
"sku":"10150926","qtyInStock":2,"qtyNetwork":4,
"qtyDC":6,"priceList":18.15,"priceSave":3.21,"priceCore":10.0}
]
}
}
]
}
]
}
];
$scope.predicate = '';
Fiddle: Fiddle
Ответы
Ответ 1
Вам может потребоваться определить очень хорошую функцию сортировщика или отсортировать products
до того, как они будут интерпретированы с помощью ng-repeat
. Я создал функцию сортировщика, используя underscore.js(или lodash).
Вы можете проверить демонстрацию (или обновленную демонстрацию). Продукты сначала сортируются по категориям, а затем сортируются по цене в каждой категории.
<!-- in html -->
<button ng-click="sortFn=sortByPrice">Sort By Price</button>
<button ng-click="sortFn=doNotSort">Do not Sort</button>
...
<div ng-repeat="val in sortFn(vals.products)">
...
// in js
$scope.sortByPrice = function(products) {
return _.sortBy(products, function(product) {
return product.length > 0 ? product[0].priceList : 0;
});
};
$scope.doNotSort = function(products) {
return products;
};
$scope.sortFn = $scope.doNotSort; // do not sort by default
BTW: Вы вызываете val[0]
прямо, что очень опасно, если продукт не содержит никаких элементов, ваш код сломается. Мой код не будет: -)
Обновление 1
Автор спрашивает меня о более чистом решении Angular.
Вот мой ответ: я думаю, что мое решение точно соответствует Angular. Обычно вы можете реализовать фильтр (похожий на orderBy
), который обертывает мой sortByPrice
. Почему я этого не делаю, потому что у вас есть ng-click
для переключения фильтра заказов. Я бы поставил логику управления в контроллер, а не на части. Это будет сложнее поддерживать, когда ваш проект будет расти.
Обновление 2
Хорошо, чтобы сделать +50
достойным, вот версия фильтра, которую вы хотите (набрав мой мозговой компилятор). Пожалуйста, зайдите в fiddle
Ответ 2
Вам нужно организовать продукты в другой структуре. Например:
$.each($scope._JSON[0].categories , function( i , e) {
$.each(e.itemTypeResults, function(sub_i,sub_e) {
$.each(sub_e.products, function(itemTypeResults_i,product) {
console.log(product);
var aProduct = new Object();
aProduct.priceList = product[0].priceList;
aProduct.name = e.name;
$scope.products.push(aProduct);
});
} )
});
Код не очень дружелюбный, но я делаю putt все продукты в одном массиве, чтобы их можно было заказывать по цене. У вас есть продукты внутри категорий, поэтому angular заказывает по цене в каждой категории.
Скрипка:
http://jsfiddle.net/7rL8fof6/1/
Надеюсь, что это поможет.
Ответ 3
Обновлена ваша скрипка: http://jsfiddle.net/k5fkocby/2/
В основном:
1. Скомпилировал сложный объект json в плоский список объектов:
var productsToShow = [];
for (var i=0; i < json[0].categories.length; i++){
var category = json[0].categories[i];
for (var j=0; j<category.itemTypeResults.length;j++){
var item = category.itemTypeResults[j];
var products = item.products;
for (var productIndex in products) {
var productItems = products[productIndex];
for (var k=0; k<productItems.length;k++){
var productItem = productItems[k];
// Additions:
productItem.categoryName = category.name;
productItem.partTerminologyName = item.partTerminologyName;
productItem.position = item.position;
productsToShow.push(productItem);
}
}
}
}
-
Показывать название категории только при необходимости:
ng-repeat = "product in (sortedProducts = (productsToShow | orderBy: предикат))"
и
ng-show="sortedProducts[$index - 1].partTerminologyName != product.partTerminologyName"
Ответ 4
вы можете сортировать из своей базы данных и получать окончательные данные JSON.
db.categories.aggregate([{$group : {category : {your condition} }, price: {$sort : { price: 1 } },}}])