Niestandardowa funkcja sortowania w powtarzaniu ng

113

Mam zestaw kafelków, które wyświetlają określoną liczbę w zależności od wybranej przez użytkownika opcji. Chciałbym teraz zaimplementować sortowanie według wyświetlanej liczby.

Poniższy kod pokazuje, jak go zaimplementowałem (pobierając / ustawiając wartość w zakresie kart nadrzędnych). Teraz, ponieważ funkcja orderBy przyjmuje ciąg, próbowałem ustawić zmienną w zakresie karty o nazwie curOptionValue i posortować według tego, ale wydaje się, że nie działa.

Powstaje więc pytanie, jak utworzyć niestandardową funkcję sortowania?

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

i kontroler:

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
źródło

Odpowiedzi:

192

W rzeczywistości orderByfiltr może przyjąć jako parametr nie tylko ciąg znaków, ale także funkcję. Z orderBydokumentacji: https://docs.angularjs.org/api/ng/filter/orderBy ):

funkcja: funkcja getter. Wynik tej funkcji zostanie posortowany przy użyciu operatora <, =,>.

Więc możesz napisać własną funkcję. Na przykład, jeśli chciałbyś porównać karty na podstawie sumy opt1 i opt2 (zmyślam, chodzi o to, że możesz mieć dowolną funkcję), napiszesz w swoim kontrolerze:

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

a następnie w swoim szablonie:

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

Oto działający plik jsFiddle

Inną rzeczą wartą odnotowania jest to, że orderByjest to tylko jeden przykład filtrów AngularJS, więc jeśli potrzebujesz bardzo konkretnego sposobu porządkowania, możesz napisać własny filtr (chociaż orderBypowinien wystarczyć w większości przypadków użycia).

pkozlowski.opensource
źródło
To miłe, ale czy można również utworzyć filtr do tego?
hugo der hungrige
Tak, nadal działa. Oto zaktualizowana wersja
jahller
Dlaczego w dokumentach nie ma opisu wielu parametrów? BTW: Dzięki, to działa. :)
mayankcpdixit
Czy wiesz, jak mogę obsłużyć wiele kryteriów za pomocą tego podejścia? Jak mogę zwrócić wiele wartości z funkcji myValueFunction?
akcasoy
26

Przyjęte rozwiązanie działa tylko na tablicach, ale nie na obiektach ani tablicach asocjacyjnych. Niestety, ponieważ Angular zależy od implementacji wyliczania tablic w języku JavaScript, kolejność właściwości obiektu nie może być konsekwentnie kontrolowana. Niektóre przeglądarki mogą iterować leksykograficznie właściwości obiektów, ale nie można tego zagwarantować.

np. biorąc pod uwagę następujące zadanie:

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

a dyrektywa <ul ng-repeat="(key, card) in cards | orderBy:myValueFunction">, ng-repeat może iterować po „card1” przed „card2”, niezależnie od kolejności sortowania.

Aby obejść ten problem, możemy utworzyć niestandardowy filtr, aby przekonwertować obiekt na tablicę, a następnie zastosować niestandardową funkcję sortowania przed zwróceniem kolekcji.

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

Nie możemy iterować po parach (klucz, wartość) w połączeniu z niestandardowymi filtrami (ponieważ klucze dla tablic są indeksami numerycznymi), więc szablon należy zaktualizować, aby odwoływał się do wstrzykniętych nazw kluczy.

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

Oto działające skrzypce wykorzystujące niestandardowy filtr na tablicy asocjacyjnej: http://jsfiddle.net/av1mLpqx/1/

Źródła: https://github.com/angular/angular.js/issues/1286#issuecomment-22193332

David
źródło
1
Wiem, że nie powinienem, ale po prostu muszę - Dzięki.
Elia Weiss
7

Poniższy link bardzo dobrze wyjaśnia filtry w Angular. Pokazuje, jak można zdefiniować niestandardową logikę sortowania w ramach powtórzenia ng. http://toddmotto.com/everything-about-custom-filters-in-angular-js

Do sortowania obiektów z właściwościami użyłem kodu: (Zwróć uwagę, że to sortowanie jest standardową metodą sortowania JavaScript, a nie specyficzną dla kątowego) Nazwa kolumny to nazwa właściwości, na której ma być wykonane sortowanie.

self.myArray.sort(function(itemA, itemB) {
    if (self.sortOrder === "ASC") {
        return itemA[columnName] > itemB[columnName];
    } else {
        return itemA[columnName] < itemB[columnName];
    }
});
Jonathan Cardoz
źródło
0

Aby dołączyć kierunek wraz z funkcją orderBy:

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

gdzie

defaultSortDirection = 0; // 0 = Ascending, 1 = Descending
Ben
źródło
emmmmm, przechodząc przez myśl, zauważyłem, że myOrderbyFunction()zamiast tego napisałeś , powinieneś pisać myOrderbyFunctionbez (), jest on wywoływany dla każdej pary elementów w celu zapewnienia niestandardowego sortowania.
Victor,