Функция пользовательской сортировки в ng-repeat

У меня есть набор плиток, которые отображают определенное число, в зависимости от того, какой параметр выбран пользователем. Теперь я хотел бы выполнить сортировку по любому номеру.

В приведенном ниже коде показано, как я его реализовал (путем gettting/установки значения в области родительских карт). Теперь, поскольку функция orderBy принимает строку, я попытался установить переменную в области карты с именем curOptionValue и отсортировать ее, но она не работает.

Итак, возникает вопрос, как создать пользовательскую функцию сортировки?

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

и контроллер:

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

Ответ 1

Фактически фильтр orderBy может принимать в качестве параметра не только строку, но и функцию. Из документации orderBy: http://docs.angularjs.org/api/ng.filter:orderBy):

Функция

: функция Getter. Результат этой функции будет отсортирован используя оператор <, =, > .

Итак, вы можете написать свою собственную функцию. Например, если вы хотите сравнить карты на основе суммы opt1 и opt2 (я делаю это, дело в том, что у вас может быть любая произвольная функция), которую вы должны написать в своем контроллере:

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

а затем в вашем шаблоне:

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

Вот рабочий jsFiddle

Следует отметить, что orderBy - это всего лишь один пример Фильтры AngularJS, поэтому, если вам нужно очень специфическое поведение порядка, вы можете написать свой собственный фильтр (хотя orderBy должно быть достаточно для большинства случаев использования).

Ответ 2

Принятое решение работает только с массивами, но не с объектами или ассоциативными массивами. К сожалению, поскольку Angular зависит от реализации перечисления массива JavaScript, порядок свойств объекта не может контролироваться последовательно. Некоторые браузеры могут проходить через свойства объекта лексикографически, но это не может быть гарантировано.

например. Учитывая следующее назначение:

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

и директива <ul ng-repeat="(key, card) in cards | orderBy:myValueFunction">, ng-repeat может перебирать "card1" до "card2", независимо от порядка сортировки.

Чтобы обойти это, мы можем создать настраиваемый фильтр для преобразования объекта в массив, а затем применить пользовательскую функцию сортировки перед возвратом коллекции.

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

Мы не можем перебирать пары (ключ, значение) в сочетании с настраиваемыми фильтрами (поскольку ключи для массивов являются числовыми индексами), поэтому шаблон должен быть обновлен для ссылки на введенные имена ключей.

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

Вот рабочая скрипка с использованием настраиваемого фильтра в ассоциативном массиве: http://jsfiddle.net/av1mLpqx/1/

Ссылка: https://github.com/angular/angular.js/issues/1286#issuecomment-22193332

Ответ 3

Следующая ссылка очень хорошо объясняет фильтры в Angular. Он показывает, как можно определить пользовательскую логику сортировки в ng-повторе. http://toddmotto.com/everything-about-custom-filters-in-angular-js

Для сортировки объекта со свойствами это код, который я использовал: (Обратите внимание, что этот вид является стандартным методом сортировки JavaScript, а не специфичным для angular). Имя столбца - это имя свойства, в котором должна выполняться сортировка.

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