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

113

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

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

Ответы:

192

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

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

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

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

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

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

Вот рабочий jsFiddle

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

pkozlowski.opensource
источник
Это хорошо, но можно ли создать фильтр и для этого?
Уго дер Хангридж,
Да, все еще работает. Вот обновленная версия
jahller
Почему в документах нет описания нескольких параметров ?? BTW: Спасибо, работает. :)
mayankcpdixit
Вы знаете, как при таком подходе я могу обрабатывать несколько критериев? Как я могу вернуть несколько значений из myValueFunction?
akcasoy
26

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

Дэвид
источник
1
Я знаю, что не должен, но я просто должен ... Спасибо.
Элия ​​Вайс
7

Следующая ссылка очень хорошо объясняет фильтры в 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];
    }
});
Джонатан Кардоз
источник
0

Чтобы включить направление вместе с функцией orderBy:

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

где

defaultSortDirection = 0; // 0 = Ascending, 1 = Descending
Бен
источник
эммммм, просто мимоходом подумав, я заметил, что вы написали myOrderbyFunction()вместо этого, вы должны писать myOrderbyFunctionбез (), он вызывается для каждой пары элементов, чтобы вы могли обеспечить пользовательскую сортировку.
Виктор