I\'m new to Angular and would like to learn the best way to handle a problem. My goal is to have a reusable means to create group by headers. I created a solution which wor
http://blog.csdn.net/violet_day/article/details/17023219#t2
<!doctype html>
<html ng-app>
<head>
<script src="lib/angular/angular.min.js"></script>
<script>
function TestCtrl($scope) {
$scope.items = [
{ id: 0, name: "Red"},
{ id: 1, name: "Red"},
{ id: 2, name: "Red"},
{ id: 3, name: "Red"},
{ id: 4, name: "Yellow"},
{ id: 5, name: "Orange"}
];
}
</script>
</head>
<body ng-controller="TestCtrl">
<ul ng-repeat="a in items" ng-if="a.name!=items[$index-1].name">
{{ a.name }}
<li ng-repeat="b in items" ng-if="a.name==b.name">
{{ b.id }}
</li>
</ul>
</body>
</html>
EDIT: here's a custom filter approach. Groups
is created by a filter function in scope to generate array of groups from current list. Adding/deleting list items will bind update of the group array as it is reset every digest cycle.
HTML
<div ng-app="myApp">
<div ng-controller='TestGroupingCtlr'>
<div ng-repeat='group in getGroups()'>
<h2>{{group}}</h2>
<ul>
<!-- could use another scope variable as predicate -->
<li ng-repeat="item in MyList | groupby:group">{{item.whatever}}</li>
</ul>
</div>
</div>
</div>
JS
var app=angular.module('myApp',[]);
app.filter('groupby', function(){
return function(items,group){
return items.filter(function(element, index, array) {
return element.GroupByFieldName==group;
});
}
})
app.controller('TestGroupingCtlr',function($scope) {
$scope.MyList = [{ GroupByFieldName: 'Group 1', whatever: 'abc'},
{GroupByFieldName: 'Group 1',whatever: 'def'},
{GroupByFieldName: 'Group 2',whatever: 'ghi' },
{GroupByFieldName: 'Group 2',whatever: 'jkl'},
{GroupByFieldName: 'Group 2',whatever: 'mno' }
];
$scope.getGroups = function () {
var groupArray = [];
angular.forEach($scope.MyList, function (item, idx) {
if (groupArray.indexOf(item.GroupByFieldName) == -1)
groupArray.push(item.GroupByFieldName)
});
return groupArray.sort();
}
})
DEMO
If you are already using LoDash/Underscore, or any functional library, you can do this using _.groupBy() (or similarly named) function.
In controller:
var movies = [{"movieId":"1","movieName":"Edge of Tomorrow","lang":"English"},
{"movieId":"2","movieName":"X-MEN","lang":"English"},
{"movieId":"3","movieName":"Gabbar Singh 2","lang":"Telugu"},
{"movieId":"4","movieName":"Resu Gurram","lang":"Telugu"}];
$scope.movies = _.groupBy(movies, 'lang');
In template:
<ul ng-repeat="(lang, langMovs) in movies">{{lang}}
<li ng-repeat="mov in langMovs">{{mov.movieName}}</li>
</ul>
This will renders:
English
Telugu
Even better, this can be also converted into a filter very easily, without much of boilerplate code to group elements by a property.
Update: Group by multiple keys
Often grouping using multiple keys is very useful. Ex, using LoDash (source):
$scope.movies = _.groupBy(movies, function(m) {
return m.lang+ "-" + m.movieName;
});
Update on why I recommend this approach:
Using filters on ng-repeat
/ng-options
causes serious perf issues unless that filter executes quickly. Google for the filters perf problem. You'll know!