2013-08-08 77 views
14

Tôi đang sử dụng AngularJs và đã tìm thấy sự cố khi sắp xếp các thuộc tính của đối tượng băm trong mẫu.
đối tượng của tôi là như sau:AngularJs sắp xếp đối tượng trong ngRepeat

function TestCtrl($scope){ 
    $scope.week = {'MONDAY': ['manuel'], 'TUESDAY': [], 'WEDNESDAY': ['valerio'], 'THURSDAY': ['manuel', 'valerio'], 'FRIDAY': []} 
} 

Bây giờ, khi tôi cố gắng để in các giá trị trong mẫu của tôi:

<div ng-repeat="(day, names) in week"> 
    <span>{{day}}</span> 
    <ul> <li ng-repeat="name in names">{{name}}</li> </ul> 
</div> 

Thứ tự của các ngày in là khác nhau: FRIDAY MONDAY THURSDAY TUESDAY WEDNESDAY

tôi đã cố gắng để áp dụng bộ lọc orderBy nhưng tôi nghĩ rằng nó không hoạt động với các đối tượng, nhưng chỉ với các mảng ...

Làm thế nào tôi có thể đặt hàng?

+0

Tôi không nghĩ rằng nó liên quan đến angularjs. Các khóa đối tượng được sắp xếp theo thứ tự bảng chữ cái theo mặc định. – AlwaysALearner

+0

@CodeHater, nó liên quan đến AngularJS và không, các khóa đối tượng sẽ không được sắp xếp theo bất kỳ cách nào trong các công cụ javascript. Điều duy nhất được mô tả trong thông số chính thức là thứ tự không thể được đảm bảo, tuy nhiên, đó là một tiêu chuẩn không thực tế rằng tất cả các trình duyệt đều giữ thứ tự các khóa đối tượng chuỗi và không sắp xếp nó. –

Trả lời

19

Theo AngularJS docs (phiên bản 1.3.20):

Bạn cần phải nhận thức rằng đặc tả JavaScript không xác định theo thứ tự nào nó sẽ trả lại chìa khóa cho một đối tượng. Để có một thứ tự xác định được đảm bảo cho các khóa, số phiên bản Angular lên đến và bao gồm 1.3 sắp xếp các phím theo thứ tự abc.

Một cách giải quyết là sử dụng một loạt các phím:

function TestCtrl($scope){ 
    $scope.week = { 
     'MONDAY': ['manuel'], 'TUESDAY': [], 
     'WEDNESDAY': ['valerio'], 'THURSDAY': ['manuel', 'valerio'],  
     'FRIDAY': []} 

    $scope.weekDays = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]; 
} 

Sử dụng mảng trong quan điểm cho lặp:

<div ng-repeat="day in weekDays"> 
    <span>{{day}}</span> 
    <ul> <li ng-repeat="name in week[day]">{{name}}</li> </ul> 
</div> 

Update từ AngularJS phiên bản 1.4.6 docs:

Phiên bản 1.4 đã xóa phân loại chữ cái. Hiện tại, chúng tôi dựa vào đơn đặt hàng được trình duyệt trả lại khi chạy for key in myObj.

+4

"Khóa đối tượng JS được sắp xếp theo thứ tự bảng chữ cái theo mặc định": Điều này không đúng. AngularJS thực hiện loại: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L345 –

+2

Đúng như vậy, @MArc, cũng có rất nhiều cuộc tranh luận đang cố gắng loại bỏ 'tính năng' này: https://github.com/angular/angular.js/issues/6210 –

+2

Bắt đầu với 1,4, các phím không được sắp xếp theo thứ tự bảng chữ cái nữa. Điều này được ghi nhận là thay đổi đột phá tại đây: https://github.com/angular/angular.js/blob/master/CHANGELOG.md#breaking-changes-6 –

6

Không có cách nào để đặt hàng các đối tượng băm như thế. Không chỉ ở góc cạnh mà trong javascript nói chung.

tôi sẽ chuyển đổi các đối tượng băm để một mảng của các đối tượng, một cái gì đó như thế:

$scope.week = [{day: 'MONDAY', names: ['manuel']}, {day: 'TUESDAY', names: []} ...]; 

Và sau đó thay đổi quan điểm một cái gì đó như thế:

<div ng-repeat="day in week|orderBy:'day'"> 
    <span>{{day.day}}</span> 
    <ul> <li ng-repeat="name in day.names">{{name}}</li> </ul> 
</div> 
+0

Một lần nữa, không đúng "Không có cách nào để đặt các đối tượng băm (...) trong javascript nói chung.": Object.keys ({ngày: 'MONDAY', tên: ['manuel']}, {day: ' TUESDAY ', tên: []}) -> trả về ["ngày", "tên"] –

+0

Những gì bạn đang đề xuất là một cách giải quyết (một cách hợp pháp) để sắp xếp các đối tượng qua một mảng khác. Không có cách nào để tự đặt hàng các đối tượng. –

+0

bạn có downvote tôi không? Dù sao tôi đã không đề nghị để thực sự sắp xếp các đối tượng.IMO đối tượng sẽ được trình bày 'như là' mà không phân loại nó. Tôi muốn loại bỏ dòng mã này từ mã nguồn của Angular: 'collectionKeys.sort();' (mã của tôi chỉ là một minh chứng) –

1

Câu hỏi này là cũ, nhưng Tôi đã kết thúc với một câu trả lời cho điều này mà tôi nghĩ có thể là một sự cải tiến trên một số câu trả lời trước đó.

Thay vì chỉ đơn giản là chuyển đổi đối tượng thành một mảng, nhiều DRY hơn để tạo bộ lọc góc làm điều đó cho bạn và sau đó là ngRepeat hoặc ngOptions.

Như một ví dụ:

angular.module('myproject') 
    .filter('objOrder', function() { 
     return function(object) { 
      var array = []; 
      angular.forEach(object, function (value, key) { 
       array.push({key: key, value: value}); 
      }); 
      return array; 
     }; 
    }); 

Sau đó, với một đối tượng như:

$scope.degrees: { 
     ASC: "Associate's", 
     BAS: "Bachelor's", 
     MAS: "Master's", 
     MD: "M.D.", 
     JD: "J.D.", 
     PHD: "Ph.D", 
     OTH: "Other" 
    } 

Chúng ta có thể sử dụng nó như vậy:

<select 
    ng-model="myDegree" 
    required 
    ng-options="item.key as item.value for item in degrees | objOrder" 
    > 
</select> 

Bằng cách này, bạn không phải tạo một mảng mới và gây ô nhiễm $scope, cũng không phải bạn phải quay lại và thay đổi đối tượng thực tế degrees của bạn có thể có tác dụng phụ không mong muốn.

+0

Đây không phải là giải pháp khả thi vì bộ lọc luôn trả về một thể hiện mới của mảng, việc kiểm tra bẩn sẽ biến mất vào vòng lặp vô hạn. –

+0

@FredYang Tôi đã sử dụng phương pháp này trong sản xuất mà không có vấn đề – jdotjdot

3

Điều này đã được sửa trong Angular 1.4. Như đã nêu trong tài liệu chính thức của Angular bên dưới:

Phiên bản 1.4 đã xóa phân loại chữ cái. Bây giờ chúng ta dựa vào thứ tự trả về bởi các trình duyệt khi chạy for key in myObj

https://docs.angularjs.org/api/ng/directive/ngRepeat

3

Có thực sự là một giải pháp đơn giản ... Các phím đối tượng không được ra lệnh theo mặc định NHƯNG nếu bạn tạo đối tượng trong trình duyệt từ đầu trình duyệt của bạn WILL biết trật tự;)

Ví dụ:

// test-1 
var data = {}; 
data['a'] = 10; 
data['b'] = 5; 
data['c'] = 2; 

Object.keys(data); // ["a", "b", "c"] 


// test-2 
var data = {}; 
data['b'] = 5; 
data['a'] = 10; 
data['c'] = 2; 

Object.keys(data); // ["b", "a", "c"] 

Vì vậy, chỉ đơn giản là ... tái tạo đối tượng ... hoặc sử dụng bộ lọc đơn giản này:

.filter('orderObject', function() { 
    return function (object, reverse) { 
     var keys = Object.keys(object || {}).sort(); 
     if (reverse) keys.reverse(); 
     for (var ordered = {}, i = 0; keys[i]; i++) { 
      ordered[keys[i]] = object[keys[i]]; 
     } 
     return ordered; 
    } 
}) 

Ví dụ với các đối tượng thường xuyên:

<!-- MARKUP : DEFAULT --> 
<table> 
    <tr ng-repeat="(key, value) in data"> 
     <td>{{key}}</td> 
     <td>{{value}}</td> 
    </tr> 
</table> 

<!-- RESULT : test-1 --> 
<table> 
    <tr> 
     <td>a</td> 
     <td>10</td> 
    </tr> 
    <tr> 
     <td>b</td> 
     <td>5</td> 
    </tr> 
    <tr> 
     <td>c</td> 
     <td>2</td> 
    </tr> 
</table> 

<!-- RESULT : test-2 --> 
<table> 
    <tr> 
     <td>b</td> 
     <td>5</td> 
    </tr> 
    <tr> 
     <td>a</td> 
     <td>10</td> 
    </tr> 
    <tr> 
     <td>c</td> 
     <td>2</td> 
    </tr> 
</table> 

Ví dụ với các đối tượng được sắp xếp:

<!-- MARKUP : with FILTER orderObject:<reverse?> --> 
<table> 
    <tr ng-repeat="(key, value) in data | orderObject"> 
     <td>{{key}}</td> 
     <td>{{value}}</td> 
    </tr> 
</table> 

<!-- RESULT : test-1 without reverse --> 
<table> 
    <tr> 
     <td>a</td> 
     <td>10</td> 
    </tr> 
    <tr> 
     <td>b</td> 
     <td>5</td> 
    </tr> 
    <tr> 
     <td>c</td> 
     <td>2</td> 
    </tr> 
</table> 

<!-- RESULT : test-2 with reverse --> 
<table> 
    <tr> 
     <td>c</td> 
     <td>2</td> 
    </tr> 
    <tr> 
     <td>b</td> 
     <td>5</td> 
    </tr> 
    <tr> 
     <td>a</td> 
     <td>10</td> 
    </tr> 
</table> 
Các vấn đề liên quan