Пользовательская функция сортировки в ng-repeat

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

код ниже показывает, как я его реализовал (путем получения/установки значения в области родительских карт). Теперь, поскольку функция 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];
    }
}]);

3 ответов


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

функция: функция добытчика. Результат этой функции будет отсортирован использование оператора.

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

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

и потом, в вашем шаблоне:

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

вот рабочий jsFiddle

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


принятое решение работает только с массивами, но не с объектами или ассоциативными массивами. К сожалению, поскольку 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-повтор может повторяться над " 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


следующая ссылка объясняет фильтры в Angular чрезвычайно хорошо. Он показывает, как можно определить пользовательскую логику сортировки в ng-repeat. 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];
    }
});