2013-08-08 24 views
14

Ich benutze AngularJs und festgestellt, ein Problem beim Anordnen von Eigenschaften eines Hash-Objekts in einer Vorlage.
Mein Ziel ist es, wie:AngularJs sort Objekt in ngRepeat

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

Jetzt, wenn ich versuche, diese Werte in meiner Vorlage zu drucken:

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

Die Reihenfolge der gedruckten Tagen anders: FRIDAY MONDAY THURSDAY TUESDAY WEDNESDAY

Ich habe versucht, um den Filter anzuwenden orderBy, aber ich denke, es funktioniert nicht mit Objekten, sondern nur mit Arrays ...

Wie kann ich es bestellen?

+0

Ich glaube nicht, dass es mit angularjs verwandt ist. Die Objektschlüssel werden standardmäßig alphabetisch sortiert. – AlwaysALearner

+0

@CodeHater, es ist AngularJS verwandt und Nein, Objektschlüssel werden in JavaScript-Engines in keiner Weise sortiert. Das einzige, was in der offiziellen Spezifikation beschrieben wird, ist, dass die Reihenfolge nicht garantiert werden kann, aber es ist ein De-facto-Standard, dass alle Browser die Reihenfolge der String-Objektschlüssel beibehalten und sie nicht sortieren. –

Antwort

19

Per AngularJS docs (Version 1.3.20):

Sie müssen sich bewusst sein, dass die JavaScript-Spezifikation nicht nicht definiert welcher Reihenfolge sie die Schlüssel für ein Objekt zurück. Um eine garantierte deterministische Reihenfolge für die Schlüssel, Winkelversionen bis zu und einschließlich 1.3 zu haben, sortieren Sie die Schlüssel alphabetisch.

Eine Abhilfe ist es, eine Anordnung von Tasten zu verwenden:

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

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

das Array in Ansicht Verwendung für Iteration:

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

Update von AngularJS Version 1.4.6 docs:

Version 1.4 hat die alphabetische Sortierung entfernt. Wir verlassen uns jetzt auf die Reihenfolge , die vom Browser zurückgegeben wird, wenn for key in myObj ausgeführt wird.

+4

"JS Objektschlüssel werden standardmäßig alphabetisch sortiert": Dies ist nicht wahr. AngularJS tut die Sortierung: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L345 –

+2

Getreu diesem, @MArc, gibt es auch eine Menge Debatte versucht zu Entfernen Sie dieses 'Feature': https://github.com/angular/angular.js/issues/6210 –

+2

Ab 1.4 werden die Schlüssel nicht mehr alphabetisch sortiert. Dies ist als eine Bruchänderung hier dokumentiert: https://github.com/angular/angular.js/blob/master/CHANGELOG.md#breaking-changes-6 –

6

Es gibt keine Möglichkeit, solche Hash-Objekte anzuordnen. Nicht nur in eckigen, sondern generell in Javascript.

würde ich das Hash-Objekt in ein Array von Objekten, so etwas konvertieren:

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

Und dann den Blick auf etwas wie das ändern:

<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

Noch einmal, nicht wahr "Es gibt keine Möglichkeit, Hash-Objekte (...) in Javascript im Allgemeinen anzuordnen.": Object.keys ({Tag: 'MONDAY', Namen: ['manuel']}, {Tag: ' DIENSTAG ', Namen: []}) -> gibt ["Tag", "Namen"] zurück –

+0

Was Sie vorschlagen, ist eine Problemumgehung (eine legitime), um Objekte über ein anderes Array zu bestellen. Es gibt keine Möglichkeit, die Objekte selbst zu bestellen. –

+0

hast du mich runtergeschmissen? Jedenfalls habe ich nicht vorgeschlagen, Objekte zu sortieren.IMO das Objekt sollte "wie es ist" präsentiert werden, ohne es zu sortieren. Ich möchte diese Codezeile aus Angulars Quellcode entfernen: 'collectionKeys.sort();' (mein Code war nur eine Demonstration) –

1

Diese Frage ist alt, aber Am Ende habe ich eine Antwort gefunden, von der ich dachte, dass sie eine Verbesserung bei einigen der vorherigen Antworten sein könnte.

Anstatt einfach das Objekt in ein Array zu konvertieren, ist es viel trockener, einen angularen Filter zu erstellen, der das für Sie erledigt, und dann ngRepeat oder ngOptions darüber.

Als Beispiel:

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

Dann mit einem Objekt wie: Sie

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

Auf diese Weise weder müssen:

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

Wir es wie so verwenden könnte Erstellen Sie ein neues Array und verschmutzen $scope, noch müssen Sie zurück und ändern Sie Ihre tatsächlichen degrees Objekt , die unerwünschte Nebenwirkungen haben könnten.

+0

Dies ist keine praktikable Lösung, da der Filter immer eine neue Instanz von Array zurückgibt, wird die schmutzige Prüfung gehen in die Infinitivschleife. –

+0

@FredYang Ich habe diese Methode in der Produktion ohne Problem verwendet – jdotjdot

3

Dies wurde in Angular 1.4 behoben. Wie in der offiziellen Angular-Dokumentation unten angegeben:

Version 1.4 entfernt die alphabetische Sortierung. Wir verlassen uns jetzt in der Größenordnung durch den Browser zurückgegeben, wenn for key in myObj

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

3

läuft Es ist eigentlich eine einfache Lösung ... Die Objektschlüssel werden standardmäßig nicht bestellt ABER, wenn Sie das schaffen Objekt im Browser von Grund auf Ihrem Browser WILL die Reihenfolge kennen;)

Beispiel:

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

So einfach ... erstellen Sie das Objekt ... oder benutzen Sie diese einfachen Filter:

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

Beispiel mit regelmäßigen Objekte:

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

Beispiel mit sortierten Objekte:

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