web-dev-qa-db-fra.com

Fonction de tri personnalisée dans ng-repeat

J'ai un ensemble de tuiles qui affichent un certain nombre en fonction de l'option sélectionnée par l'utilisateur. Je voudrais maintenant mettre en œuvre un tri par le nombre indiqué.

Le code ci-dessous montre comment je l'ai implémenté (en sélectionnant/définissant une valeur dans l'étendue des cartes parent). Maintenant, comme la fonction orderBy prend une chaîne, j'ai essayé de définir une variable dans l'étendue de la carte appelée curOptionValue et de trier en fonction de cela, mais cela ne semble pas fonctionner.

La question est donc de savoir comment créer une fonction de tri personnalisée.

<div ng-controller="aggViewport" >
<div class="btn-group" >
    <button ng-click="setOption(opt.name)" ng-repeat="opt in optList" class="btn active">{{opt.name}}</button>
</div>
<div id="container" iso-grid width="500px" height="500px">
    <div ng-repeat="card in cards" class="item {{card.class}}" ng-controller="aggCardController">
        <table width="100%">
            <tr>
                <td align="center">
                    <h4>{{card.name}}</h4>
                </td>
            </tr>
            <tr>
                <td align="center"><h2>{{getOption()}}</h2></td>
            </tr>
        </table>        
    </div>
</div>

et contrôleur: 

module.controller('aggViewport',['$scope','$location',function($scope,$location) {
    $scope.cards = [
        {name: card1, values: {opt1: 9, opt2: 10}},
        {name: card1, values: {opt1: 9, opt2: 10}}
    ];

    $scope.option = "opt1";

    $scope.setOption = function(val){
        $scope.option = val;
    }

}]);

module.controller('aggCardController',['$scope',function($scope){
    $scope.getOption = function(){
        return $scope.card.values[$scope.option];
    }
}]);
108
user1167650

En réalité, le filtre orderBy peut prendre comme paramètre non seulement une chaîne, mais également une fonction. De la documentation orderBy: https://docs.angularjs.org/api/ng/filter/orderBy ):

fonction: fonction Getter. Le résultat de cette fonction sera trié en utilisant l'opérateur <, =,>.

Donc, vous pouvez écrire votre propre fonction. Par exemple, si vous souhaitez comparer des cartes basées sur une somme de opt1 et opt2 (je fais cela, le fait est que vous pouvez avoir n'importe quelle fonction), vous écririez dans votre contrôleur:

$scope.myValueFunction = function(card) {
   return card.values.opt1 + card.values.opt2;
};

et ensuite, dans votre modèle:

ng-repeat="card in cards | orderBy:myValueFunction"

Voici le jsFiddle de travail

L'autre chose à noter est que orderBy n'est qu'un exemple de filtres AngularJS donc si vous avez besoin d'un comportement de commande très spécifique, vous pouvez écrire votre propre filtre (bien que orderBy soit suffisant pour la plupart des cas d'utilisation).

187

La solution acceptée ne fonctionne que sur les tableaux, mais pas sur les objets ou les tableaux associatifs. Malheureusement, comme Angular dépend de l'implémentation JavaScript de l'énumération de tableaux, l'ordre des propriétés de l'objet ne peut pas être contrôlé de manière cohérente. Certains navigateurs peuvent parcourir les propriétés des objets lexicographiquement, mais cela ne peut pas être garanti.

par exemple. Étant donné la mission suivante:

$scope.cards = {
  "card2": {
    values: {
      opt1: 9,
      opt2: 12
    }
  },
  "card1": {
    values: {
      opt1: 9,
      opt2: 11
    }
  }
};

et la directive <ul ng-repeat="(key, card) in cards | orderBy:myValueFunction">, ng-repeat peut itérer sur "carte1" avant "carte2", quel que soit l'ordre de tri.

Pour contourner ce problème, nous pouvons créer un filtre personnalisé pour convertir l'objet en un tableau, puis appliquer une fonction de tri personnalisé avant de renvoyer la collection.

myApp.filter('orderByValue', function () {
  // custom value function for sorting
  function myValueFunction(card) {
    return card.values.opt1 + card.values.opt2;
  }

  return function (obj) {
    var array = [];
    Object.keys(obj).forEach(function (key) {
      // inject key into each object so we can refer to it from the template
      obj[key].name = key;
      array.Push(obj[key]);
    });
    // apply a custom sorting function
    array.sort(function (a, b) {
      return myValueFunction(b) - myValueFunction(a);
    });
    return array;
  };
});

Nous ne pouvons pas itérer sur des paires (clé, valeur) conjointement avec des filtres personnalisés (car les clés des tableaux sont des index numériques), le modèle doit donc être mis à jour pour faire référence aux noms de clé injectés.

<ul ng-repeat="card in cards | orderByValue">
    <li>{{card.name}} {{value(card)}}</li>
</ul>

Voici un violon qui utilise un filtre personnalisé sur un tableau associatif: http://jsfiddle.net/av1mLpqx/1/

Référence: https://github.com/angular/angular.js/issues/1286#issuecomment-22193332

26
David

Le lien suivant explique extrêmement bien les filtres angulaires. Il montre comment il est possible de définir une logique de tri personnalisée dans ng-repeat . http://toddmotto.com/everything-about-custom-filters-in-angular-js

Pour le tri d’objet avec propriétés, c’est le code que j’ai utilisé:.

self.myArray.sort(function(itemA, itemB) {
    if (self.sortOrder === "ASC") {
        return itemA[columnName] > itemB[columnName];
    } else {
        return itemA[columnName] < itemB[columnName];
    }
});
7
Jonathan Cardoz

Pour inclure la direction avec la fonction orderBy:

ng-repeat="card in cards | orderBy:myOrderbyFunction():defaultSortDirection"

defaultSortDirection = 0; // 0 = Ascending, 1 = Descending
0
Ben