ng-repeatのカスタムソート関数


113

ユーザーが選択したオプションに応じて特定の数を表示するタイルのセットがあります。ここで、表示されている数値による並べ替えを実装したいと思います。

以下のコードは、私がそれをどのように実装したかを示しています(親カードのスコープで値を取得/設定することにより)。さて、orderBy関数は文字列を受け取るため、curOptionValueと呼ばれるカードスコープに変数を設定して並べ替えようとしましたが、機能しないようです。

だから問題は、どうやってカスタムソート関数を作成するのですか?

<div ng-controller="aggViewport" >
<div class="btn-group" >
    <button ng-click="setOption(opt.name)" ng-repeat="opt in optList" class="btn active">{{opt.name}}</button>
</div>
<div id="container" iso-grid width="500px" height="500px">
    <div ng-repeat="card in cards" class="item {{card.class}}" ng-controller="aggCardController">
        <table width="100%">
            <tr>
                <td align="center">
                    <h4>{{card.name}}</h4>
                </td>
            </tr>
            <tr>
                <td align="center"><h2>{{getOption()}}</h2></td>
            </tr>
        </table>        
    </div>
</div>

およびコントローラー:

module.controller('aggViewport',['$scope','$location',function($scope,$location) {
    $scope.cards = [
        {name: card1, values: {opt1: 9, opt2: 10}},
        {name: card1, values: {opt1: 9, opt2: 10}}
    ];

    $scope.option = "opt1";

    $scope.setOption = function(val){
        $scope.option = val;
    }

}]);

module.controller('aggCardController',['$scope',function($scope){
    $scope.getOption = function(){
        return $scope.card.values[$scope.option];
    }
}]);

回答:


192

実際には、orderByフィルタは文字列だけでなく関数もパラメータとしてとることができます。orderByドキュメントから:https : //docs.angularjs.org/api/ng/filter/orderBy):

function:ゲッター関数。この関数の結果は、<、=、>演算子を使用してソートされます。

したがって、独自の関数を作成できます。たとえば、opt1とopt2の合計に基づいてカードを比較したい場合(私はこれを作り上げていますが、ポイントは、任意の関数を持つことができるということです)、コントローラーに書き込みます。

$scope.myValueFunction = function(card) {
   return card.values.opt1 + card.values.opt2;
};

そして、あなたのテンプレートで:

ng-repeat="card in cards | orderBy:myValueFunction"

これが動作しているjsFiddleです

注目に値するもうorderBy1つのことは、AngularJSフィルターのほんの一例であるため、非常に特定の順序付け動作が必要な場合は、独自のフィルターを作成できます(ただしorderBy、ほとんどのユースケースで十分です)。


それはいいですが、そのためのフィルターを作成することもできますか?
hugo der hungrige 2013

はい、まだ機能しています。これが更新されたバージョンです
jahller 2013

ドキュメントに複数のパラメータに関する説明がないのはなぜですか?ところで:ありがとう、それは機能します。:)
mayankcpdixit 2014年

このアプローチで複数の基準をどのように処理できるか知っていますか?myValueFunctionから複数の値を返すにはどうすればよいですか?
akcasoy、2015年

26

承認されたソリューションは、配列でのみ機能し、オブジェクトや連想配列では機能しません。残念ながら、Angularは配列列挙のJavaScript実装に依存しているため、オブジェクトプロパティの順序を一貫して制御することはできません。一部のブラウザは、オブジェクトのプロパティを辞書式に反復処理する場合がありますが、これは保証されません。

たとえば、次の割り当てがあるとします。

$scope.cards = {
  "card2": {
    values: {
      opt1: 9,
      opt2: 12
    }
  },
  "card1": {
    values: {
      opt1: 9,
      opt2: 11
    }
  }
};

そして指令 <ul ng-repeat="(key, card) in cards | orderBy:myValueFunction"> ng-repeatは、並べ替え順序に関係なく、「card2」の前に「card1」を反復処理できます。

これを回避するには、カスタムフィルターを作成してオブジェクトを配列に変換し、コレクションを返す前にカスタムソート関数を適用します。

myApp.filter('orderByValue', function () {
  // custom value function for sorting
  function myValueFunction(card) {
    return card.values.opt1 + card.values.opt2;
  }

  return function (obj) {
    var array = [];
    Object.keys(obj).forEach(function (key) {
      // inject key into each object so we can refer to it from the template
      obj[key].name = key;
      array.push(obj[key]);
    });
    // apply a custom sorting function
    array.sort(function (a, b) {
      return myValueFunction(b) - myValueFunction(a);
    });
    return array;
  };
});

(配列のキーは数値インデックスであるため)カスタムフィルターと組み合わせて(キー、値)の組み合わせを反復処理できないため、注入されたキー名を参照するようにテンプレートを更新する必要があります。

<ul ng-repeat="card in cards | orderByValue">
    <li>{{card.name}} {{value(card)}}</li>
</ul>

これは、連想配列でカスタムフィルターを利用する作業フィドルです。 。http //jsfiddle.net/av1mLpqx/1/

リファレンス:https : //github.com/angular/angular.js/issues/1286#issuecomment-22193332


1
私はすべきでないことを知っていますが、私はしなければなりません-ありがとう。
エリアワイス

7

次のリンクは、Angularのフィルターについて非常によく説明しています。これは、ng-repeat内でカスタムソートロジックを定義する方法を示しています。 http://toddmotto.com/everything-about-custom-filters-in-angular-js

プロパティ付きのオブジェクトの並べ替えの場合、これは私が使用したコードです(この並べ替えはJavaScriptの標準の並べ替えメソッドであり、angularに固有ではないことに注意してください)。列名は、並べ替えが実行されるプロパティの名前です。

self.myArray.sort(function(itemA, itemB) {
    if (self.sortOrder === "ASC") {
        return itemA[columnName] > itemB[columnName];
    } else {
        return itemA[columnName] < itemB[columnName];
    }
});

0

orderBy関数とともに方向を含めるには:

ng-repeat="card in cards | orderBy:myOrderbyFunction():defaultSortDirection"

どこ

defaultSortDirection = 0; // 0 = Ascending, 1 = Descending

emmmmm、あなたが書いたと私が観察するmyOrderbyFunction()代わりに、あなたはmyOrderbyFunctionなし()で書くべきだと思っただけで 、カスタムのソートを提供するために要素の2つのペアごとに呼び出されます。
ビクター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.