Спеціальна функція сортування у ng-повторі


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

Відповіді:


192

Насправді 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має вистачити для більшості випадків використання).


Це приємно, але чи можна створити фільтр і для цього?
hugo der hungrige

Так, це все ще працює. Ось оновлена ​​версія
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-повтор може перебирати "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/isissue/1286#issuecomment-22193332


1
Я знаю, що не повинен, але просто повинен - ​​Спасибі.
Елія Вайс

7

Наступне посилання пояснює фільтри в кутовій надзвичайно добре. Він показує, як можна визначити логіку сортування користувача у межах ng-повтору. http://toddmotto.com/everything-about-custom-filters-in-angular-js

Для сортування об'єкта з властивостями це код, який я використав: (Зверніть увагу, що цей сорт є стандартним методом сортування JavaScript, а не специфічним для кутових) Ім'я стовпця - це ім'я властивості, за яким слід проводити сортування.

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без цього (), він отримує посилання на кожну дві пари елементів для того, щоб надати власну сортування.
Віктор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.