Oltre alle risposte accettate sopra, ho creato un filtro generico "groupBy" utilizzando la libreria underscore.js.
JSFiddle (aggiornato):
http://jsfiddle.net/TD7t3/
Il filtro
app.filter('groupBy', function() {
return _.memoize(function(items, field) {
return _.groupBy(items, field);
}
);
});
Nota la chiamata 'memoize'. Questo metodo di sottolineatura memorizza nella cache il risultato della funzione e impedisce che angolare valuti ogni volta l'espressione del filtro, evitando così che angolare raggiunga il limite di iterazioni digest.
L'html
<ul>
<li ng-repeat="(team, players) in teamPlayers | groupBy:'team'">
{{team}}
<ul>
<li ng-repeat="player in players">
{{player.name}}
</li>
</ul>
</li>
</ul>
Applichiamo il nostro filtro "groupBy" sulla variabile dell'ambito teamPlayers, sulla proprietà "team". La nostra ng-repeat riceve una combinazione di (chiave, valori []) che possiamo usare nelle seguenti iterazioni.
Aggiornamento dell'11 giugno 2014
Ho ampliato il gruppo per filtro per tenere conto dell'uso delle espressioni come chiave (ad esempio variabili nidificate). Il servizio di analisi angolare è molto utile per questo:
Il filtro (con supporto per le espressioni)
app.filter('groupBy', function($parse) {
return _.memoize(function(items, field) {
var getter = $parse(field);
return _.groupBy(items, function(item) {
return getter(item);
});
});
});
Il controller (con oggetti nidificati)
app.controller('homeCtrl', function($scope) {
var teamAlpha = {name: 'team alpha'};
var teamBeta = {name: 'team beta'};
var teamGamma = {name: 'team gamma'};
$scope.teamPlayers = [{name: 'Gene', team: teamAlpha},
{name: 'George', team: teamBeta},
{name: 'Steve', team: teamGamma},
{name: 'Paula', team: teamBeta},
{name: 'Scruath of the 5th sector', team: teamGamma}];
});
L'html (con espressione sortBy)
<li ng-repeat="(team, players) in teamPlayers | groupBy:'team.name'">
{{team}}
<ul>
<li ng-repeat="player in players">
{{player.name}}
</li>
</ul>
</li>
JSFiddle:
http://jsfiddle.net/k7fgB/2/