Sắp xếp AngularJS theo thuộc tính


93

Những gì tôi đang cố gắng làm là sắp xếp một số dữ liệu theo thuộc tính. Đây là ví dụ mà tôi nghĩ nên làm việc nhưng nó không.

Phần 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>

Phần 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},
    }

}]);

Và kết quả:

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

... IMHO đó sẽ trông như thế này:

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

Tôi có bỏ lỡ điều gì không ( JSFiddle ở đây đã sẵn sàng để thử nghiệm)?

Câu trả lời:


148

Bộ lọc orderBy của AngularJS chỉ hỗ trợ mảng - không có đối tượng. Vì vậy, bạn phải viết một bộ lọc nhỏ riêng để phân loại cho bạn.

Hoặc thay đổi định dạng dữ liệu mà bạn xử lý (nếu bạn có ảnh hưởng đến điều đó). Một mảng chứa các đối tượng có thể sắp xếp theo thứ tự gốc bằng bộ lọc.

Đây là bộ lọc orderObjectBy của tôi cho 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;
 }
});

Cách sử dụng theo quan điểm của bạn:

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

Trong ví dụ này, đối tượng cần thuộc tính vị trí, nhưng bạn có thể linh hoạt sử dụng bất kỳ thuộc tính nào trong các đối tượng (chứa một số nguyên), chỉ theo định nghĩa trong chế độ xem.

JSON mẫu:

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

Đây là một fiddle hiển thị cho bạn cách sử dụng: http://jsfiddle.net/4tkj8/1/


1
Điều đó thật tuyệt. Tôi đã thêm tùy chọn để sắp xếp asc / desc: app.filter ('orderObjectBy', function () {return function (input, thuộc tính, direction) {if (! Angle.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 [property]) ; trả về hướng == 'asc'? a - b: b - a;}); trả về mảng;}}); Trong HTML: <tr ng-repeat = "val in list | orderObjectBy: 'prop': 'asc'">
Jazzy

@Armin thì sao nếu đây là đối tượng như mảng? tức là{1:'Example 1', 2:'Example 2', 3:'Example 3', ...}
Eugene

8
Câu trả lời tuyệt vời NHƯNG chúng tôi đã đánh mất chìa khóa của đối tượng theo cách này. Để giữ cho nó, chỉ cần thêm nó tạo ra hàng mảng mới trong bộ lọc, ví dụ for(var objectKey in input) { input[objectKey]['_key'] = objectKey; array.push(input[objectKey]); }như chúng ta có thể sử dụng<div ng-repeat="value in object | orderObjectBy:'order'" ng-init="key = value['_key']">
Nicolas Janel

7
Nó đáng chú ý là Angular.js không hỗ trợ sắp xếp theo một tài sản trong một mảng của các đối tượng bây giờ: ... | orderBy: 'name'.
Wildhoney

2
@Wildhoney Câu hỏi này là về thứ tự các đối tượng bằng khóa, không phải mảng chứa đối tượng.
Armin

31

Nó khá dễ dàng, chỉ cần làm như thế này

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

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

33
Điều này không hoạt động đối với các mảng liên kết, đó là những gì câu hỏi về.
MFB

7

Đừng quên rằng parseInt () chỉ hoạt động cho các giá trị Số nguyên. Để sắp xếp các giá trị chuỗi, bạn cần hoán đổi điều này:

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

Với cái này:

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

6

Như bạn có thể thấy trong mã của angle-JS ( https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js ) ng-repeat không hoạt động với các đối tượng. Đây là một bản hack với 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

theo http://docs.angularjs.org/api/ng.filter:orderBy , orderBy sắp xếp một mảng. Trong trường hợp của bạn, bạn đang chuyển một đối tượng, vì vậy Bạn sẽ phải triển khai chức năng sắp xếp của riêng Bạn.

hoặc truyền một mảng -

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

hãy xem tại http://jsfiddle.net/qaK56/


Tôi biết rằng nó hoạt động với mảng .. Vì vậy, giải pháp là viết hàm sắp xếp của riêng tôi?
PrimosK

Your jsfiddle! = Mã của bạn mà bạn đã đăng. Đây là jsfiddle phù hợp cho ví dụ của bạn ở đây: jsfiddle.net/qaK56/92
mrzmyr

3

Bạn thực sự nên cải thiện cấu trúc JSON của mình để khắc phục sự cố của mình:

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

Sau đó, bạn có thể làm

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

Tôi nghĩ rằng vấn đề là các biến (khóa, giá trị) không có sẵn cho bộ lọc orderBy và bạn không nên lưu trữ dữ liệu trong các khóa của mình


2
nói điều đó với Firebase;)
MFB

như xa như tôi biết, bạn tạo ra các dữ liệu trong căn cứ hỏa lực
Joshua Wooward

Nếu bạn lưu trữ một mảng trong Firebase, nó sử dụng UID làm khóa cho mảng. Có nhiều tình huống mà người ta không kiểm soát được cấu trúc dữ liệu, vì vậy đề xuất của bạn có thể hơi sâu.
MFB

lưu trữ một mảng những gì? Người ta luôn có quyền kiểm soát cấu trúc dữ liệu. Ngoài ra, OP không đề cập gì đến Firebase.
Joshua Wooward

2

Đây là những gì tôi đã làm và nó hoạt động.
Tôi vừa sử dụng một đối tượng được xâu chuỗi.

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

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

nếu tôi muốn sắp xếp theo văn bản, tôi sẽ làm

orderBy : 'mostRecent.text'

2

Tôi sẽ thêm phiên bản bộ lọc đã nâng cấp có thể hỗ trợ cú pháp tiếp theo:

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

Cảm ơn Armin và Jason vì câu trả lời của họ trong chủ đề này và Alnitak trong chủ đề này .


1

Câu trả lời của Armin + kiểm tra chặt chẽ các loại đối tượng và các phím không góc cạnh như $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

Điều sau đây cho phép sắp xếp thứ tự của các đối tượng theo khóa HOẶC theo một khóa trong một đối tượng .

Trong mẫu, bạn có thể làm một số việc như:

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

Hoặc thậm chí:

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

Bộ lọc:

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

Có bình thường không khi các khóa của (k, i) trong objectList được chuyển đổi thành 0 và 1?
Ken Vernaillen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.