web-dev-qa-db-fra.com

Orderby ne fonctionne pas avec la syntaxe dict sur ng-repeat

J'essaie d'utiliser ng-repeat avec une syntaxe de style dictionnaire et d'appliquer un ordre à la valeur de clé.

(key, value) in something | orderBy:'key' 

Il semble que OrderBy ne fonctionne pas comme prévu

Exemple ici http://jsfiddle.net/mhXuW/

38
Cameron Singe

Les paramètres à orderBy doivent correspondre aux noms de propriété dans un tableau d'objets.

Vos données doivent ressembler à ceci:

$scope.list2 = [ { id:"2013-01-08T00:00:00", name:'Joe'},
                 { id:"2013-01-09T00:00:00", name:'Sue'}];

Ensuite, un filtre comme celui-ci fonctionnera:

<div ng-repeat="item in list2 | orderBy:'id':true">

Fiddle .

Notez que orderBy fonctionne sur tout le tableau (something dans votre exemple de code ci-dessus) et renvoie un tableau trié. orderBy ne sait rien de key et value.

19
Mark Rajcok

ceci n'est pas implémenté. s'il vous plaît voir ici:

https://github.com/angular/angular.js/issues/1286

EDIT (27 août 2013): ce problème semble être résolu maintenant.

11
akonsu

J'ai créé un filtre personnalisé pour rendre cela possible pour une liste de sélection:

.filter('toDictionaryArray', function () {
    return function (obj) {
        if (!(obj instanceof Object)) return obj;

        var arr = [];
        for (var key in obj) {
            arr.Push({ key: key, value: obj[key] });
        }
        return arr;
    }
})

la liste de sélection ng-options se lit alors comme suit:

<select ng-options="kv.key as kv.value for kv in p.options | toDictionaryArray | orderBy:'value'"></select>
6
Peter Riesz

Voici un bon travail autour de ( angular-toArrayFilter ):

.filter('toArray', function () {
  return function (obj, addKey) {
    if ( addKey === false ) {
      return Object.keys(obj).map(function(key) {
        return obj[key];
      });
    } else {
      return Object.keys(obj).map(function (key) {
        if(typeof obj[key] == 'object') return Object.defineProperty(obj[key], '$key', {     enumerable: false, value: key});
      });
    }
  };
});
2
joseym

Comme le dit Akonsu, la fonctionnalité a été demandée ici . Cependant, je ne pouvais toujours pas le faire fonctionner avec la dernière version bêta (1.3.0).

Il existe une solution de contournement Nice dans les commentaires (notez que underscore est nécessaire, et vous devrez remplacer les références à 'clé' par 'valeur. $ Clé' dans l'exemple ci-dessus):

[Ajouter un filtre]:

app.filter('toArray', function() { return function(obj) {
    if (!(obj instanceof Object)) return obj;
    return _.map(obj, function(val, key) {
        return Object.defineProperty(val, '$key', {__proto__: null, value: key});
    });
}});

Exemple de balisage:

<div ng-repeat="val in object | toArray | orderBy:'priority' | filter:fieldSearch">
  {{val.$key}} : {{val}} 
</div>

Inconvénients potentiels:

  • Object.defineProperty ne fonctionnera pas comme ceci dans IE8 (si vous ne le faites pas Si vous voulez que la clé soit énumérable, il s'agit d'un changement facile). 
  • Si vos valeurs de propriété ne sont pas des objets, vous ne pouvez pas définir la propriété $ key et cela échoue.
  • Il n'est pas directement intégré à orderBy ou ngRepeat donc la syntaxe est différente.
2
Dunc

Au lieu d'utiliser orderby filter, qui ne prend en charge que les tableaux et non les objets. Vous pouvez écrire votre propre filtre comme celui-ci. J'ai pris le code de Justin Klemm http://justinklemm.com/angularjs-filter-ordering-objects-ngrepeat/ et un support supplémentaire pour la spécification de champs de commande multiples. L'exemple de filtre ci-dessous consiste à filtrer en fonction des propriétés dans les valeurs, mais vous pouvez également le modifier pour le filtrer en fonction de la clé.

app.filter('orderObjectBy', function()
{
    return function(items, fields, reverse)
    {
        var filtered = [];
        angular.forEach(items, function(item)
        {
            filtered.Push(item);
        });

        filtered.sort(function (a, b)
        {
            var result = 0;

            for (var i = 0; i < fields.length; ++i)
            {
                if (a[fields[i]] > b[fields[i]])
                {
                    result = 1;
                    break;
                }
                else if (a[fields[i]] < b[fields[i]])
                {
                    result = -1;
                    break;
                }
            }

            return result;
        });

        if (reverse)
        {
            filtered.reverse();
        }

        return filtered;
    };
});

Ensuite, dans votre page Web html5, utilisez-la comme suit: où statistiques est une carte/dictionnaire avec des paires valeur/clé. 

<div class="row" ng-repeat="stat in statistics | orderObjectBy: 'NumTimesPartnered', 'NumTimesOpponent']:true">
    <div class="col col-33">{{stat.Name}}</div>
    <div class="col"><center>{{stat.NumTimesPartnered}}</center></div>
    <div class="col"><center>{{stat.NumTimesOpponent}}</center></div>
</div>
0
Patrick Tan