各グループに属するプレーヤーのリストがあります。フィルターを使用してグループごとのユーザーを一覧表示するにはどうすればよいですか?
[{name: 'Gene', team: 'team alpha'},
{name: 'George', team: 'team beta'},
{name: 'Steve', team: 'team gamma'},
{name: 'Paula', team: 'team beta'},
{name: 'Scruath of the 5th sector', team: 'team gamma'}];
私はこの結果を探しています:
angular.filter モジュールのgroupByを使用できます。
したがって、次のようなことができます。
JS:
$scope.players = [
{name: 'Gene', team: 'alpha'},
{name: 'George', team: 'beta'},
{name: 'Steve', team: 'gamma'},
{name: 'Paula', team: 'beta'},
{name: 'Scruath', team: 'gamma'}
];
HTML:
<ul ng-repeat="(key, value) in players | groupBy: 'team'">
Group name: {{ key }}
<li ng-repeat="player in value">
player: {{ player.name }}
</li>
</ul>
結果:
グループ名:アルファ
*プレーヤー:ジーン
グループ名:ベータ
*プレーヤー:ジョージ
*プレーヤー:ポーラ
グループ名:ガンマ
*プレーヤー:スティーブ
*プレーヤー:スクルース
UPDATE:jsbinangular.filter
を使用するための基本的な要件を覚えておいてください。具体的には、モジュールの依存関係に追加する必要があることに注意してください。
(1)4つの異なる方法を使用して、角度フィルターをインストールできます。
- このリポジトリのクローンと構築
- bower経由:端末から$ bower install angle-filterを実行して
- npm経由:$ npmを実行して、端末からangular-filterをインストールします
- cdnjs経由 http://www.cdnjs.com/libraries/angular-filter
(2)Angular自体を含めた後、index.htmlにangle-filter.js(またはangular-filter.min.js)を含めます。
(3) 'angular.filter'をメインモジュールの依存関係のリストに追加します。
上記の受け入れられた回答に加えて、underscore.jsライブラリーを使用して一般的な「groupBy」フィルターを作成しました。
JSFiddle(更新済み): http://jsfiddle.net/TD7t3/
フィルター
app.filter('groupBy', function() {
return _.memoize(function(items, field) {
return _.groupBy(items, field);
}
);
});
「memoize」コールに注意してください。このアンダースコアメソッドは、関数の結果をキャッシュし、angularが毎回フィルター式を評価するのを停止するため、angularがダイジェストの反復制限に達するのを防ぎます。
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>
「group」フィルタは、teamPlayersスコープ変数の「team」プロパティに適用します。 ng-repeatは、次の反復で使用できる(key、values [])の組み合わせを受け取ります。
2014年6月11日更新キーとして式を使用することを考慮して、フィルターごとにグループを拡張しました(ネストされた変数など)。 angular解析サービスは、このために非常に便利です。
フィルター(式サポート付き)
app.filter('groupBy', function($parse) {
return _.memoize(function(items, field) {
var getter = $parse(field);
return _.groupBy(items, function(item) {
return getter(item);
});
});
});
コントローラ(ネストされたオブジェクトを使用)
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}];
});
html(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/
最初に、一意のチームのみを返すフィルターを使用してループを実行し、次に現在のチームごとにすべてのプレーヤーを返すネストされたループを実行します。
http://jsfiddle.net/plantface/L6cQN/
html:
<div ng-app ng-controller="Main">
<div ng-repeat="playerPerTeam in playersToFilter() | filter:filterTeams">
<b>{{playerPerTeam.team}}</b>
<li ng-repeat="player in players | filter:{team: playerPerTeam.team}">{{player.name}}</li>
</div>
</div>
スクリプト:
function Main($scope) {
$scope.players = [{name: 'Gene', team: 'team alpha'},
{name: 'George', team: 'team beta'},
{name: 'Steve', team: 'team gamma'},
{name: 'Paula', team: 'team beta'},
{name: 'Scruath of the 5th sector', team: 'team gamma'}];
var indexedTeams = [];
// this will reset the list of indexed teams each time the list is rendered again
$scope.playersToFilter = function() {
indexedTeams = [];
return $scope.players;
}
$scope.filterTeams = function(player) {
var teamIsNew = indexedTeams.indexOf(player.team) == -1;
if (teamIsNew) {
indexedTeams.Push(player.team);
}
return teamIsNew;
}
}
元々Plantfaceの答えを使用していましたが、構文がどのように表示されるかが気に入らなかった。
$ q.defer を使用してデータを後処理し、一意のチームのリストを返すように作り直しました。これがフィルターとして使用されます。
http://plnkr.co/edit/waWv1donzEMdsNMlMHBa?p=preview
<ul>
<li ng-repeat="team in teams">{{team}}
<ul>
<li ng-repeat="player in players | filter: {team: team}">{{player.name}}</li>
</ul>
</li>
</ul>
app.controller('MainCtrl', function($scope, $q) {
$scope.players = []; // omitted from SO for brevity
// create a deferred object to be resolved later
var teamsDeferred = $q.defer();
// return a promise. The promise says, "I promise that I'll give you your
// data as soon as I have it (which is when I am resolved)".
$scope.teams = teamsDeferred.promise;
// create a list of unique teams. unique() definition omitted from SO for brevity
var uniqueTeams = unique($scope.players, 'team');
// resolve the deferred object with the unique teams
// this will trigger an update on the view
teamsDeferred.resolve(uniqueTeams);
});
両方の答えが良かったので、それらをディレクティブに移動して再利用可能にし、2番目のスコープ変数を定義する必要がないようにしました。
ここにフィドルがあります 実装を確認したい場合
以下はディレクティブです:
var uniqueItems = function (data, key) {
var result = [];
for (var i = 0; i < data.length; i++) {
var value = data[i][key];
if (result.indexOf(value) == -1) {
result.Push(value);
}
}
return result;
};
myApp.filter('groupBy',
function () {
return function (collection, key) {
if (collection === null) return;
return uniqueItems(collection, key);
};
});
その後、次のように使用できます。
<div ng-repeat="team in players|groupBy:'team'">
<b>{{team}}</b>
<li ng-repeat="player in players | filter: {team: team}">{{player.name}}</li>
</div>
Ariel Mによって提案されたソリューションの古いバージョンが提案したため、最初にこの回答を書きました。 他の$filter
sと組み合わせた場合 がトリガーされた "Infite $ diggest Loop Error "(infdig
) 幸いなことに、この問題は angular.filter の最新バージョンで解決されています。
次の実装を提案しました その問題はありませんでした :
angular.module("sbrpr.filters", [])
.filter('groupBy', function () {
var results={};
return function (data, key) {
if (!(data && key)) return;
var result;
if(!this.$id){
result={};
}else{
var scopeId = this.$id;
if(!results[scopeId]){
results[scopeId]={};
this.$on("$destroy", function() {
delete results[scopeId];
});
}
result = results[scopeId];
}
for(var groupKey in result)
result[groupKey].splice(0,result[groupKey].length);
for (var i=0; i<data.length; i++) {
if (!result[data[i][key]])
result[data[i][key]]=[];
result[data[i][key]].Push(data[i]);
}
var keys = Object.keys(result);
for(var k=0; k<keys.length; k++){
if(result[keys[k]].length===0)
delete result[keys[k]];
}
return result;
};
});
ただし、この実装はAngular 1.3より前のバージョンでのみ機能します。 (すべてのバージョンで動作するソリューションを提供するこの回答をすぐに更新します。)
私は実際に この$filter
を開発するためにとったステップ、私が遭遇した問題、そしてそこから学んだことについての投稿を書きました 。
複数列でグループ化する場合は、受け入れられた回答に加えてこれを使用できます。
<ul ng-repeat="(key, value) in players | groupBy: '[team,name]'">
Jsコードで必要な場合。 angula-filter libの注入メソッドを使用できます。このような。
function controller($scope, $http, groupByFilter) {
var groupedData = groupByFilter(originalArray, 'groupPropName');
}
https://github.com/a8m/angular-filter/wiki/Common-Questions#inject-filters