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

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

У меня примерно так:

<div ng-repeat="item in items | orderBy:memberSort">
  {{item.sortName}} / {{item.description}}
</div>

И компаратор:

$scope.memberSort = function(m1, m2) {
    if (m1.description && !m2.description) {
       return -1;
    }
    if (m2.description && !m1.description) {
       return 1;
    }
    return m1.sortName.localCompare(m2.sortName);
};

Как я могу использовать такой компаратор, а не только функцию значения с одним параметром? В приведенном выше коде параметр m2 всегда не определен.

Вот jsfiddle: https://jsfiddle.net/1Lwg4s2r/15/

Хотя это всего лишь одна текущая проблема, общий вопрос заключается в том, как определить функцию компаратора, принимающую 2 значения, а не только однопараметрическую функцию, которая сопоставляет сложный объект со значением?

4
EasterBunnyBugSmasher 13 Мар 2018 в 01:50

2 ответа

Лучший ответ

Вы должны были указать компаратор memberSort в качестве третьего аргумента orderBy:

angular.module('app', []).controller('myController', function($scope) {
  $scope.items = [    
    { description: '', sortName: 'Bob' },
    { description: '', sortName: 'Steve' },
    { description: '', sortName: 'Mark' },
    { description: 'Member', sortName: 'Kirk' },
    { description: 'Boss', sortName: 'Joe' }
  ];
  $scope.memberSort = function(o1, o2) {
    var m1 = o1.value, m2 = o2.value;
    if (m1.description && !m2.description)
       return -1;    
    if (m2.description && !m1.description)
       return 1;    
    return m1.sortName.localeCompare(m2.sortName);
  };
});
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>

<div ng-app='app' ng-controller="myController">
  <div ng-repeat="item in items | orderBy: 'valueOf()' : false : memberSort">  
    {{item.sortName}} / {{item.description}}
  </div>
</div>
3
Slava Utesinov 13 Мар 2018 в 06:44

Начиная с angularjs 1.5.7 канал Angularjs OrderBy может принимать функцию в качестве компаратора, но я думаю, что гораздо проще связать функцию, которая возвращает отсортированный массив, используя JavaScript array.sort ().

JSFIDDLE

HTML

<div ng-repeat="item in getSortedItems()">
  {{item.sortName}} / {{item.description}}
</div>

JS

function myCtrl($scope) {
   $scope.items = [
      {description: 'Boss',sortName: 'Joe'},
      //... rest of your items
   ];

   $scope.getSortedItems = function() {
       return $scope.items.sort(function(m1, m2) {
           if (m1.description && !m2.description)
               return -1;

           if (m2.description && !m1.description)
               return 1;

           return m1.sortName.localeCompare(m2.sortName);
       });
   };
}

Если вам важна производительность, не используйте фильтры angularjs для выполнения простых задач , таких как сортировка массива. Хотя в моем решении функция сортировки выполняется дважды (было бы лучше, если вы можете отсортировать массив, а затем присвоить значение связанной переменной), в принятом решении выполняется 20 раз.

3
The.Bear 16 Мар 2018 в 01:17