2013-08-08 14 views
14

Używam AngularJs i znalazłem problem z porządkowaniem właściwości obiektu haszującego w szablonie.
Moim celem jest jak:Obiekt sortowania AngularJs w ngRepeat

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

Teraz, gdy próbuję wydrukować te wartości w moim szablonu:

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

Kolejność dni drukowanych jest inna: FRIDAY MONDAY THURSDAY TUESDAY WEDNESDAY

próbowałem zastosować filtr orderBy, ale myślę, że nie działa z obiektami, ale tylko z tablicami ...

Jak mogę to zamówić?

+0

Nie sądzę, że jest to związane z angularjs. Klawisze obiektów są domyślnie sortowane alfabetycznie. – AlwaysALearner

+0

@CodeHater, jest powiązany z AngularJS i nie, klucze obiektowe nie będą sortowane w żaden sposób w silnikach javascript. Jedyną rzeczą opisaną w oficjalnej specyfikacji jest to, że zamówienie nie może być zagwarantowane, ale jest to de facto standardem, że wszystkie przeglądarki utrzymują porządek kluczy obiektów ciągowych i nie sortują ich. –

Odpowiedz

19

Zgodnie angularjs docs (wersja 1.3.20):

Trzeba mieć świadomość, że specyfikacja JavaScript nie definiuje jakiej kolejności zwróci klucze do obiektu. Aby mieć gwarantowaną deterministyczną kolejność dla kluczy, , wersje Angular do i 1.3 sortuj alfabetycznie alfabetycznie.

Rozwiązaniem jest użycie tablicę klawiszy:

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

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

użyć tablicę ze względu na iteracji:

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

Aktualizacja z wersji 1.4.6 docs angularjs:

Wersja 1.4 usunęła sortowanie alfabetyczne. Teraz polegamy na zamówieniu zwróconym przez przeglądarkę podczas uruchamiania for key in myObj.

+4

"Klawisze obiektów JS są domyślnie sortowane alfabetycznie": To nie jest prawda. AngularJS robi coś takiego: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L345 –

+2

To prawda, @MArc, jest też wiele debat próbujących usuń tę "cechę": https://github.com/angular/angular.js/issues/6210 –

+2

Począwszy od wersji 1.4 klucze nie są sortowane alfabetycznie. Zostało to udokumentowane jako przełomowa zmiana: https://github.com/angular/angular.js/blob/master/CHANGELOG.md#breaking-changes-6 –

6

Nie ma sposobu, aby zamówić takie obiekty hashowe. Nie tylko w kanciastym, ale w javascriptie w ogóle.

Chciałbym przekształcić obiekt hash do tablicy obiektów, coś w tym:

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

a następnie zmienić pogląd na coś takiego:

<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

Znowu nie jest prawdą "Nie ma sposobu na zamawianie obiektów hash (...) w javascript w ogóle.": Object.keys ({dzień: 'PONIEDZIAŁEK', imiona: ['manuel']}, {day: ' WTOREK ", imiona: []}) -> zwraca [" dzień "," imiona "] –

+0

Proponujemy obejście (uzasadnienie) do zamawiania obiektów za pomocą innej tablicy. Nie ma możliwości zamawiania samych obiektów. –

+0

czy mnie scharakteryzowałeś? W każdym razie nie sugerowałem, aby właściwie sortować przedmioty.IMO obiekt powinien być przedstawiony "tak jak jest" bez sortowania go. Chciałbym usunąć ten wiersz kodu z kodu źródłowego Angular: 'collectionKeys.sort();' (mój kod był tylko demonstracją) –

1

to pytanie jest stary, ale Skończyło się na tym, że wymyśliłem odpowiedź na to, co moim zdaniem może poprawić niektóre z poprzednich odpowiedzi.

Zamiast po prostu przekształcić obiekt w tablicę, jest o wiele bardziej SUCHE stworzenie filtru kątowego, który robi to za Ciebie, a następnie nad nim ngRepeat lub .

Jako przykład:

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

Następnie z obiektu takich jak:

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

Możemy używać go tak:

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

W ten sposób nie trzeba utworzyć nową tablicę i zanieczyszczać $scope, nie musisz też wracać i zmieniać rzeczywistego obiektu degrees , które mogą mieć niepożądane skutki uboczne.

+0

To nie jest praktyczne rozwiązanie, ponieważ filtr zawsze zwraca nową instancję tablicy, brudne sprawdzenie przejdzie w nieskończoną pętlę. –

+0

@FredYang Użyłem tej metody w produkcji bez problemu – jdotjdot

3

Zostało to naprawione w ustawieniu kątowym 1.4. Zgodnie z oficjalną dokumentacją Angular poniżej:

Wersja 1.4 usunęła sortowanie alfabetyczne. Mamy teraz polegać na zlecenie zwracany przez przeglądarkę podczas pracy for key in myObj

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

3

jest rzeczywiście proste rozwiązanie ... Klucze do obiektu nie są sortowane według Domyślnie BUT jeśli utworzyć obiekt w przeglądarce od podstaw swoją przeglądarkę WILL znać kolejność;)

Przykład:

// 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"] 

... Więc po prostu odtworzyć obiekt ... lub użyć tego prostego filtra:

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

Przykład z regularnych obiektów:

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

Przykład z posortowanych obiektów:

<!-- 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> 
Powiązane problemy