プロパティによるAngularJSの並べ替え


93

私がやろうとしていることは、いくつかのデータをプロパティでソートすることです。これは私が働いたはずの例ですが、うまくいきません。

HTML部分:

<div ng-app='myApp'>
    <div ng-controller="controller">
    <ul>
        <li ng-repeat="(key, value) in testData | orderBy:'value.order'">
            {{value.order}}. {{key}} -> {{value.name}}
        </li>
    </ul>
    </div>
</div>

JSパート:

var myApp = angular.module('myApp', []);

myApp.controller('controller', ['$scope', function ($scope) {

    $scope.testData = {
        C: {name:"CData", order: 1},
        B: {name:"BData", order: 2},
        A: {name:"AData", order: 3},
    }

}]);

そしてその結果:

  1. A-> AData
  2. B-> BData
  3. C-> CData

... IMHOは次のようになるはずです。

  1. C-> CData
  2. B-> BData
  3. A-> AData

私は何かを見逃しましたか(ここで、JSFiddleを試す準備ができています)?

回答:


148

AngularJSのorderByフィルターは配列のみをサポートし、オブジェクトはサポートしません。そのため、ソートを行う独自の小さなフィルターを作成する必要があります。

または、扱うデータの形式を変更します(それに影響がある場合)。オブジェクトを含む配列は、ネイティブのorderByフィルターでソートできます。

AngularJSのorderObjectByフィルターは次のとおりです。

app.filter('orderObjectBy', function(){
 return function(input, attribute) {
    if (!angular.isObject(input)) return input;

    var array = [];
    for(var objectKey in input) {
        array.push(input[objectKey]);
    }

    array.sort(function(a, b){
        a = parseInt(a[attribute]);
        b = parseInt(b[attribute]);
        return a - b;
    });
    return array;
 }
});

あなたの見解での使い方:

<div class="item" ng-repeat="item in items | orderObjectBy:'position'">
    //...
</div>

この例ではオブジェクトに位置属性が必要ですが、ビュー内の定義により、オブジェクト(整数を含む)で任意の属性を使用する柔軟性があります。

JSONの例:

{
    "123": {"name": "Test B", "position": "2"},
    "456": {"name": "Test A", "position": "1"}
}

これは使用方法を示すフィドルです:http : //jsfiddle.net/4tkj8/1/


1
これは素晴らしい。asc / descをソートするオプションを追加しました:app.filter( 'orderObjectBy'、function(){return function(input、attribute、direction){if(!angular.isObject(input))return input; var array = [] ; for(var objectKey in input){array.push(input [objectKey]);} array.sort(function(a、b){a = parseInt(a [attribute]); b = parseInt(b [attribute]) ; return direction == 'asc'?a-b:b-a;}); return array;}}); HTML:<tr ng-repeat = "val in list | orderObjectBy: 'prop': 'asc'">
Jazzy

@Arminこれが配列のようなオブジェクトの場合はどうなりますか?すなわち{1:'Example 1', 2:'Example 2', 3:'Example 3', ...}
ユージン

8
すばらしい答えですが、この方法でオブジェクトのキーを失いました。ただそれは、フィルタなどで新しい配列の行を作成追加し、それを維持するために、for(var objectKey in input) { input[objectKey]['_key'] = objectKey; array.push(input[objectKey]); }我々が使用できるような<div ng-repeat="value in object | orderObjectBy:'order'" ng-init="key = value['_key']">
ニコラ・ジャネル

7
Angular.js オブジェクトの配列のプロパティによる並べ替えをサポートするようになったことは注目に値します:... | orderBy: 'name'
Wildhoney 2014年

2
@Wildhoneyこの質問は、オブジェクトを含む配列ではなく、キーを持つオブジェクトの順序付けについてです。
Armin

31

とても簡単です、このようにしてください

$scope.props = [{order:"1"},{order:"5"},{order:"2"}]

ng-repeat="prop in props | orderBy:'order'"

33
これは、連想配列では機能しません。これが問題です。
MFB 2014

7

parseInt()は整数値に対してのみ機能することを忘れないでください。文字列値をソートするには、これを交換する必要があります。

array.sort(function(a, b){
  a = parseInt(a[attribute]);
  b = parseInt(b[attribute]);
  return a - b;
});

これとともに:

array.sort(function(a, b){
  var alc = a[attribute].toLowerCase(),
      blc = b[attribute].toLowerCase();
  return alc > blc ? 1 : alc < blc ? -1 : 0;
});

6

angular-JSのコード(https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js)を見るとわかるように、ng-repeatはオブジェクトでは機能しません。これがsortFunctionのハックです。

http://jsfiddle.net/sunnycpp/qaK56/33/

<div ng-app='myApp'>
    <div ng-controller="controller">
    <ul>
        <li ng-repeat="test in testData | orderBy:sortMe()">
            Order = {{test.value.order}} -> Key={{test.key}} Name=:{{test.value.name}}
        </li>
    </ul>
    </div>
</div>

myApp.controller('controller', ['$scope', function ($scope) {

    var testData = {
        a:{name:"CData", order: 2},
        b:{name:"AData", order: 3},
        c:{name:"BData", order: 1}
    };
    $scope.testData = _.map(testData, function(vValue, vKey) {
        return { key:vKey, value:vValue };
    }) ;
    $scope.sortMe = function() {
        return function(object) {
            return object.value.order;
        }
    }
}]);

4

http://docs.angularjs.org/api/ng.filter:orderByに従って、orderByは配列をソートします。あなたの場合、オブジェクトを渡すので、あなた自身のソート関数を実装する必要があります。

または配列を渡します-

$scope.testData = {
    C: {name:"CData", order: 1},
    B: {name:"BData", order: 2},
    A: {name:"AData", order: 3},
}

http://jsfiddle.net/qaK56/を見てください


私はそれが配列で動作することを知っています。だから、解決策は自分のソート関数を書くことですか?
PrimosK 2013年

あなたのjsfiddle!=あなたが投稿したコード これは、ここでの例に適したjsfiddleです。jsfiddle.net
qaK56

3

問題を修正するには、JSON構造を本当に改善する必要があります。

$scope.testData = [
   {name:"CData", order: 1},
   {name:"BData", order: 2},
   {name:"AData", order: 3},
]

その後、あなたはできる

<li ng-repeat="test in testData | orderBy:order">...</li>

問題は、(キー、値)変数がorderByフィルターで利用できないことであり、データをキーに保存しないでください。


2
それをFirebaseに伝えてください;)
MFB 2014

私の知る限り、
Firebaseで

Firebaseに配列を保存する場合、配列のキーとしてUIDを使用します。データ構造を制御できない状況がたくさんあるので、あなたの提案は少し抜本的なものかもしれません。
MFB 2014

何の配列を保存しますか?常にデータ構造を制御できます。また、OPはFirebaseについて何も言及していません。
ジョシュアウーワード2014

2

これが私がやったことであり、うまくいきます。
文字列化されたオブジェクトを使用しました。

$scope.thread = [ 
  {
    mostRecent:{text:'hello world',timeStamp:12345678 } 
    allMessages:[]
  }
  {MoreThreads...}
  {etc....}
]

<div ng-repeat="message in thread | orderBy : '-mostRecent.timeStamp'" >

テキストで並べ替えたい場合は、

orderBy : 'mostRecent.text'

2

次の構文をサポートできるフィルタのアップグレードバージョンを追加します。

ng-repeat="(id, item) in $ctrl.modelData | orderObjectBy:'itemProperty.someOrder':'asc'

app.filter('orderObjectBy', function(){

         function byString(o, s) {
            s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            s = s.replace(/^\./, '');           // strip a leading dot
            var a = s.split('.');
            for (var i = 0, n = a.length; i < n; ++i) {
                var k = a[i];
                if (k in o) {
                    o = o[k];
                } else {
                    return;
                }
            }
            return o;
        }

        return function(input, attribute, direction) {
            if (!angular.isObject(input)) return input;

            var array = [];
            for(var objectKey in input) {
                if (input.hasOwnProperty(objectKey)) {
                    array.push(input[objectKey]);
                }
            }

            array.sort(function(a, b){
                a = parseInt(byString(a, attribute));
                b = parseInt(byString(b, attribute));
                return direction == 'asc' ? a - b : b - a;
            });
            return array;
        }
    })

このスレッドで回答してくれたArminとJason、このスレッドでAlnitakに感謝します


1

Arminの回答+オブジェクトタイプと非角度キーなどの厳密なチェック $resolve

app.filter('orderObjectBy', function(){
 return function(input, attribute) {
    if (!angular.isObject(input)) return input;

    var array = [];
    for(var objectKey in input) {
      if (typeof(input[objectKey])  === "object" && objectKey.charAt(0) !== "$")
        array.push(input[objectKey]);
    }

    array.sort(function(a, b){
        a = parseInt(a[attribute]);
        b = parseInt(b[attribute]);
        return a - b;
    });

    return array;
 }
})

1

以下は、キーまたはオブジェクト内のキーによるオブジェクトの順序付けを可能にします

テンプレートでは次のようなことができます:

    <li ng-repeat="(k,i) in objectList | orderObjectsBy: 'someKey'">

あるいは:

    <li ng-repeat="(k,i) in objectList | orderObjectsBy: 'someObj.someKey'">

フィルター:

app.filter('orderObjectsBy', function(){
 return function(input, attribute) {
    if (!angular.isObject(input)) return input;

    // Filter out angular objects.
    var array = [];
    for(var objectKey in input) {
      if (typeof(input[objectKey])  === "object" && objectKey.charAt(0) !== "$")
        array.push(input[objectKey]);
    }

    var attributeChain = attribute.split(".");

    array.sort(function(a, b){

      for (var i=0; i < attributeChain.length; i++) {
        a = (typeof(a) === "object") && a.hasOwnProperty( attributeChain[i]) ? a[attributeChain[i]] : 0;
        b = (typeof(b) === "object") && b.hasOwnProperty( attributeChain[i]) ? b[attributeChain[i]] : 0;
      }

      return parseInt(a) - parseInt(b);
    });

    return array;
 }
})

objectListの(k、i)のキーが0と1に変換されるのは正常ですか?
Ken Vernaillen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.