Niestandardowa funkcja filtru AngularJS

91

W moim kontrolerze chciałbym przefiltrować tablicę obiektów. Każdy z tych obiektów jest mapą, która może zawierać zarówno ciągi znaków, jak i listy

Próbowałem użyć $filter('filter')(array, function)formatu, ale nie wiem, jak uzyskać dostęp do poszczególnych elementów tablicy w mojej funkcji. Oto fragment pokazujący, czego chcę.

$filter('filter')(array, function() {
  return criteriaMatch(item, criteria);
});

A następnie w sekcji criteriaMatch()sprawdzę, czy każda z właściwości jest zgodna

var criteriaMatch = function(item, criteria) {
  // go thro each individual property in the item and criteria
  // and check if they are equal
}

Muszę to wszystko zrobić w kontrolerze i skompilować listę list i ustawić je w zakresie. Muszę więc uzyskać dostęp tylko w $filter('filter')ten sposób. Wszystkie przykłady, które do tej pory znalazłem w sieci, zawierają statyczne kryteria wyszukiwania wewnątrz funkcji, nie przekazują obiektu kryteriów i nie testują każdego elementu w tablicy.

user2368436
źródło
3
Dlaczego potrzebujesz filtra? Zwykle filtry są używane z szablonów. Czy nie możesz po prostu mieć zwykłej funkcji w swoim kontrolerze, jeśli używasz jej tylko stamtąd?
Ketan
zamiast ręcznie przechodzić przez każdy element tablicy, pomyślałem, że możemy użyć funkcji $ filter ('filter') angular (która zajmie się iteracją każdego elementu, jeśli tylko określimy funkcję predykatu)
user2368436

Odpowiedzi:

174

Możesz go używać w ten sposób: http://plnkr.co/edit/vtNjEgmpItqxX5fdwtPi?p=preview

Tak jak znalazłeś, filterakceptuje funkcję predykatu, która akceptuje element po pozycji z tablicy. Musisz więc po prostu utworzyć funkcję predykatu na podstawie danego criteria.

W tym przykładzie criteriaMatchjest funkcją, która zwraca funkcję predykatu, która pasuje do podanego criteria.

szablon:

<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
  {{ item }}
</div>

zakres:

$scope.criteriaMatch = function( criteria ) {
  return function( item ) {
    return item.name === criteria.name;
  };
};
Bzdury
źródło
Nie będę używał tej funkcji CriterMatch z html .. jak mam to wywołać z wnętrza kontrolera, czy to jest poprawne? $ filter ('filter') (tablica, funkcja () {return kryteriumMatch (pozycja, kryterium);});
user2368436
6
Jeśli nie używasz go w swoim szablonie, zdefiniowanie filtra nie daje żadnej korzyści. Możesz po prostu zdefiniować prostą funkcję javascript, ponieważ jest tam jeszcze krótsza. Możesz użyć filtermetody natywnej w obiekcie Array:array.filter(function(item){return item.name === criteria.name;})
Tosh
Mam funkcję javascript. Chciałem się tylko upewnić, że Angular nie ma prostszego sposobu na zrobienie tego. Przyjmuję Twoją odpowiedź dzięki.
user2368436
2

Oto przykład, jak należy użyć filterw swoim JavaScript AngularJS (zamiast w elemencie HTML).

W tym przykładzie mamy tablicę rekordów krajów, z których każdy zawiera nazwę i 3-znakowy kod ISO.

Chcemy napisać funkcję, która przeszuka tę listę w poszukiwaniu rekordu pasującego do określonego 3-znakowego kodu.

Oto, jak byśmy to zrobili bez użycia filter:

$scope.FindCountryByCode = function (CountryCode) {
    //  Search through an array of Country records for one containing a particular 3-character country-code.
    //  Returns either a record, or NULL, if the country couldn't be found.
    for (var i = 0; i < $scope.CountryList.length; i++) {
        if ($scope.CountryList[i].IsoAlpha3 == CountryCode) {
            return $scope.CountryList[i];
        };
    };
    return null;
};

Tak, nic w tym złego.

Ale oto jak wyglądałaby ta sama funkcja, używając filter:

$scope.FindCountryByCode = function (CountryCode) {
    //  Search through an array of Country records for one containing a particular 3-character country-code.
    //  Returns either a record, or NULL, if the country couldn't be found.

    var matches = $scope.CountryList.filter(function (el) { return el.IsoAlpha3 == CountryCode; })

    //  If 'filter' didn't find any matching records, its result will be an array of 0 records.
    if (matches.length == 0)
        return null;

    //  Otherwise, it should've found just one matching record
    return matches[0];
};

Dużo schludniej.

Pamiętaj, że filterjako wynik zwraca tablicę (listę pasujących rekordów), więc w tym przykładzie będziemy chcieli zwrócić 1 rekord lub NULL.

Mam nadzieję że to pomoże.

Mike Gledhill
źródło
0

Dodatkowo, jeśli chcesz użyć filtra w swoim kontrolerze w taki sam sposób, jak tutaj:

<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
  {{ item }}
</div>

Możesz zrobić coś takiego:

var filteredItems =  $scope.$eval('items | filter:filter:criteriaMatch(criteria)');
cafesanu
źródło
6
Ewentualnievar filteredItems = $filter('criteriaMatch')(items, criteria);
321zeno