AngularJS mengurutkan berdasarkan properti

93

Apa yang saya coba lakukan adalah mengurutkan beberapa data menurut properti. Berikut adalah contoh yang menurut saya harus berhasil tetapi tidak.

Bagian 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>

Bagian 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},
    }

}]);

Dan hasilnya:

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

... IMHO itu akan terlihat seperti ini:

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

Apakah saya melewatkan sesuatu (ini JSFiddle siap untuk bereksperimen)?

PrimosK
sumber

Jawaban:

148

Filter orderBy AngularJS tidak hanya mendukung array - tidak ada objek. Jadi, Anda harus membuat filter kecil sendiri, yang melakukan penyortiran untuk Anda.

Atau ubah format data yang Anda tangani (jika Anda memiliki pengaruh di dalamnya). Larik yang berisi objek dapat diurutkan dengan filter orderBy asli.

Berikut adalah filter orderObjectBy saya untuk AngularJS:

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;
 }
});

Penggunaan dalam pandangan Anda:

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

Objek membutuhkan dalam contoh ini atribut posisi, tetapi Anda memiliki fleksibilitas untuk menggunakan atribut apa pun dalam objek (berisi integer), hanya dengan definisi dalam tampilan.

Contoh JSON:

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

Berikut adalah biola yang menunjukkan penggunaannya: http://jsfiddle.net/4tkj8/1/

Armin
sumber
1
Ini bagus. Saya menambahkan opsi untuk mengurutkan asc / desc: app.filter ('orderObjectBy', function () {return function (input, atribut, direction) {if (! Angular.isObject (input)) return input; var array = [] ; untuk (var objectKey in input) {array.push (input [objectKey]);} array.sort (fungsi (a, b) {a = parseInt (a [atribut]); b = parseInt (b [atribut]) ; return direction == 'asc'? a - b: b - a;}); return array;}}); Dalam HTML: <tr ng-repeat = "val in list | orderObjectBy: 'prop': 'asc'">
Jazzy
@Armin bagaimana jika ini adalah objek seperti array? yaitu{1:'Example 1', 2:'Example 2', 3:'Example 3', ...}
Eugene
8
Jawaban bagus TAPI kami kehilangan kunci objek dengan cara ini. Untuk menyimpannya, cukup tambahkan itu membuat baris array baru di filter misalnya for(var objectKey in input) { input[objectKey]['_key'] = objectKey; array.push(input[objectKey]); }Seperti yang bisa kita gunakan<div ng-repeat="value in object | orderObjectBy:'order'" ng-init="key = value['_key']">
Nicolas Janel
7
Itu perlu dicatat bahwa Angular.js melakukan dukungan menyortir oleh sebuah properti di array obyek sekarang: ... | orderBy: 'name'.
Wildhoney
2
@Wildhoney Pertanyaan ini tentang mengurutkan objek dengan kunci, bukan array yang berisi objek.
Armin
31

Sangat mudah, lakukan saja seperti ini

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

ng-repeat="prop in props | orderBy:'order'"
Leon
sumber
33
Ini tidak berfungsi untuk array asosiatif, yang merupakan pertanyaan tentang apa.
MFB
7

Jangan lupa bahwa parseInt () hanya berfungsi untuk nilai Integer. Untuk mengurutkan nilai string Anda perlu menukar ini:

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

dengan ini:

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

Seperti yang Anda lihat di kode angular-JS ( https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js ) ng-repeat tidak bekerja dengan objek. Ini adalah peretasan dengan sortFungsi.

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;
        }
    }
}]);
SunnyShah
sumber
4

menurut http://docs.angularjs.org/api/ng.filter:orderBy , orderBy mengurutkan sebuah array. Dalam kasus Anda, Anda mengirimkan objek, jadi Anda harus menerapkan fungsi penyortiran Anda sendiri.

atau lewati array -

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

lihat di http://jsfiddle.net/qaK56/

Gal Ben-Haim
sumber
Saya tahu bahwa ini bekerja dengan array .. Jadi solusinya adalah menulis fungsi penyortiran saya sendiri?
PrimosK
Your jsfiddle! = Kode yang Anda posting. Ini adalah jsfiddle yang tepat untuk contoh Anda di sini: jsfiddle.net/qaK56/92
mrzmyr
3

Anda harus benar-benar meningkatkan struktur JSON Anda untuk memperbaiki masalah Anda:

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

Maka Anda bisa melakukannya

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

Masalahnya, menurut saya, adalah bahwa variabel (key, value) tidak tersedia untuk filter orderBy, dan Anda tidak boleh menyimpan data di kunci Anda.

Joshua Wooward
sumber
2
katakan itu ke Firebase;)
MFB
Sejauh yang saya tahu, Anda membuat data di firebase
Joshua Wooward
Jika Anda menyimpan sebuah array di Firebase, itu menggunakan UID sebagai kunci untuk array tersebut. Ada banyak situasi di mana seseorang tidak dapat mengontrol struktur data, jadi saran Anda mungkin sedikit berlebihan.
MFB
menyimpan array apa? Seseorang selalu memiliki kendali atas struktur data. Juga OP tidak menyebutkan apa-apa tentang Firebase.
Joshua Wooward
2

Inilah yang saya lakukan dan berhasil.
Saya baru saja menggunakan objek yang dirangkai.

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

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

jika saya ingin mengurutkan berdasarkan teks saya akan melakukannya

orderBy : 'mostRecent.text'
James Harrington
sumber
2

Saya akan menambahkan versi filter saya yang ditingkatkan yang dapat mendukung sintaks berikutnya:

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;
        }
    })

Terima kasih kepada Armin dan Jason atas jawaban mereka di utas ini, dan Alnitak di utas ini .

TachikomaGT
sumber
1

Jawaban Armin + pemeriksaan ketat untuk tipe objek dan kunci non-sudut seperti $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;
 }
})
momen dipol
sumber
1

Berikut ini memungkinkan untuk pengurutan objek dengan kunci ATAU dengan kunci dalam suatu objek .

Dalam template Anda dapat melakukan sesuatu seperti:

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

Atau bahkan:

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

Filter:

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;
 }
})
momen dipol
sumber
apakah normal bahwa kunci (k, i) di objectList diubah menjadi 0 dan 1?
Ken Vernaillen