Witam w kolejnym odcinku serii poświęconej Angularowi 1.6. Niniejszy wpis chciałbym w całości poświęcić technice filtrowania. Angular czynność tą rozumie dwojako, w pierwszej kolejności filtrowanie pozwala nam na modyfikację, przeformatowanie danych pod kątem naszych potrzeb (dodanie waluty, zmiana wielkości liter itp.). W drugiej kolejności filtrowanie danych umożliwia ich sortowanie. Oznacza to, iż możemy posortować dane według wybranego kryterium, bądź też tworzyć własne, rozbudowane funkcje sortujące. Na koniec, filtrowanie, to także proces selekcji danych. Angular pozwala nam na wybranie z kolekcji tylko tych danych, dla których spełnione są kryteria wyboru.
Tradycyjnie, nasze filtry będziemy implementować w kodzie z poprzedniego wpisu (http://blog.pawelkaminski.net/angular-js-routing-struktura-aplikacji-czesc-7/), a będąc precyzyjnym, zajmiemy się widokiem postów. Zechcemy rozbudować go, właśnie przy użyciu filtrów.
Tak jak zostało wspomniane wcześniej, Angular definiuje filtry na kilka sposobów. Zaczynamy więc od modyfikacji danych, które to modyfikacje mogą dotyczyć:
– pojedyńczego elementu kolekcji
– całej kolekcji.
Angular udostępnia następujące filtry:
currency | formatowanie walutowe |
date | obsługa dat |
json | formatuje wartość jako kod JSON |
number | formatuje jako liczbę |
lowercase | zamienia wszystkie litery tekstu na małe |
uppercase | zamienia wszystkie litery tekstu na wielkie |
Spróbujmy użyć filtru w praktyce, sprawmy by wszystkie litery treści posta zostały zamienione na wielkie:
views/partials/posts.html
1 2 3 4 5 6 7 8 |
<div ng-controller="PostsController as vm"> <h1>Posts</h1> <ul > <li ng-repeat="x in vm.postsfromapiservice.items" ng-class-odd="'nieparzysty'" ng-class-even="'parzysty'"> {{ x.id}} | {{x.body | uppercase}} </li> </ul> </div> |
Jak widzimy filtr dotyczący konkretnego pola umieszczamy tuż za odwołaniem, poprzedzając znakiem |. Analogicznie spróbujmy podać przykładowe użycie dla poszczególnych filtrów:
Nazwa | Przykład użycia | Przykładowy efekt |
currency | {{fieldName | currency: “PLN” }} | 12,90 PLN |
date | {{dateField | date: “dd-MM-yyyy HH:mm” }} możliwe użycie z aliasami: {{dateField | date: “medium” }} aliasy: medium – MM d y h:mm:ss short – M/d/yy h:mm a fullDate – EEEE MMMM d y mediumTime – h:mm:ss a shortTime- h:mm a longDate – MMMM d y mediumDate – MMM d y shortDate – M/d/yy |
24-12-2010 18:27 |
json | <li ng-repeat=”x in collection”> {{ x | json}} </li> |
reprezentacja x w JSON |
number | val = 123.9
{{val | number:0 }} |
124 |
lowercase | val = ‘Tekst’;
{{val | uppercase }} |
TEKST |
uppercase | val = ‘Tekst’;
{{val | lowercase }} |
tekst |
Przejdźmy do filtrów kolekcji. Jednym z podstawowych filtrów z tej grupy jest limitTo. Umożliwia on limitowanie zbioru/kolekcji, która użyta jest do modyfikacji widoku. W naszym przypadku spróbujmy dodać formatkę input w celu umożliwienia modyfikacji ilości postów wyświetlanych na liście:
views/partials/posts.html
1 2 3 4 5 6 7 8 9 |
<div ng-controller="PostsController as vm"> <h1>Posts</h1> Ilosc postow: <input ng-model="vm.count" /> <ul > <li ng-repeat="x in vm.postsfromapiservice.items | limitTo:vm.count" ng-class-odd="'nieparzysty'" ng-class-even="'parzysty'"> {{ x.id}} | {{x.body | uppercase}} </li> </ul> </div> |
Dwie subtelne zmiany w kodzie to dodanie wcześniej wspomnianego elementu formularza, a także dodanie do ng-repeat filtra LimitTo: z wartością przypisaną do elementu stworzonego wyżej formularza. Dzięki temu utworzone zostanie wiązanie, a czego rezultatem będzie umożliwienie użytkownikowi zmianę ilości wyświetlanych postów:
Tym prostym przykładem przeszliśmy do filtrów, które nie tylko formatują, ale także segregują i wykonują selekcję, w powyższym przykładzie wybierają 10 pierwszych rekordów. Kolejny przykład także opierał się będzie na selekcji danych, ale w bardziej ciekawy sposób, spróbujemy mianowicie dodać wyszukiwarkę, która będze wybierała tylko te rekordy, w których zawartościach występować będą ciągi znaków zdefiniowane przez użytkownika.
W tym celu potrzebować będziemy kolejnego elementu formularza, tym razem do przechowywania wyszukiwanej frazy:
1 |
Wyszukiwarka: <input ng-model="vm.query" /> |
Kolejny krok to modyfikacja naszego ng-repeat, dołączenie filtru wyszukującego dane:
1 |
<li ng-repeat="x in vm.postsfromapiservice.items | filter:vm.query | limitTo:vm.count" ng-class-odd="'nieparzysty'" ng-class-even="'parzysty'"> |
Efekt od razu widać na ekranie:
Nasza prosta wyszukiwarka powinna działać znakomicie. Mamy już filtrowanie danych względem treści, mamy ograniczanie ilości rekordów, spróbujmy teraz zająć się sortowaniem. Standardowo rozpocznijmy od implementacji nowego elementu formularza – listy, na której użytkownicy będą mogli definiować typ sortowania:
1 2 3 4 5 6 7 |
Sortowanie <select ng-model="vm.sorting"> <option value="body">Tresc (Rosnąco)</option> <option value="id">ID (Rosnąco)</option> <option value="-body">Tresc (Malejąco)</option> <option value="-id">ID (Malejąco)</option> </select> |
Jako wartości poszczególnych elementów listy podajemy nazwy pól, w dwóch wersjach, w wersji malejącej poprzedzone znakiem minusa.
Zmienić musimy również nasz ng-repeat, dodajemy orderBy z zmieną vm.sorting, w której to przechowujemy wybór użytkownika.
1 |
<li ng-repeat="x in vm.postsfromapiservice.items | filter:vm.query | orderBy:vm.sorting | limitTo:vm.count" ng-class-odd="'nieparzysty'" ng-class-even="'parzysty'"> |
Wynik działania naszego kodu jest zgodny z oczekiwaniami – użytkownik może sortować rosnąco lub malejąco po wybranej kolumnie. Co natomiast gdy chcielibyśmy, by system sortował po dwóch polach? Sytuacja taka będzie miała miejsce, gdy pole, po którym będzie wykonywane pierwsze sortowanie będzie posiadało duplikaty. Wtedy to możemy zdefiniować kolejne kolumny, po których należy wykonać operację szeregowania. Aby osiągnąć taki rezultat Angular pozwala nam na przekazanie do orderBy tablicy z nazwami pól, bądź też co ciekawe zmiennymi lub funkcjami, które będą definiować rodzaj sortowania:
1 |
<li ng-repeat="x in vm.postsfromapiservice.items | filter:vm.query | orderBy:[vm.mojaFunkcja, vm.sorting] | limitTo:vm.count" ng-class-odd="'nieparzysty'" ng-class-even="'parzysty'"> |
Dodajmy jeszcze checkbox do włączania lub wyłączania naszej funkcji liczącej długość pola body:
1 |
Moja funkcja <input type="checkbox" ng-model="vm.mojaFunkcjaOn"/> |
W pliku postController.js:
1 2 3 4 5 |
vm.mojaFunkcja = function(record){ return record.body.length; } |
Powyższe użycie funkcji mojaFunkcja zaowocuje kolejnością sortowania:
– po długości pola body
– po polu body
– po polu id
Ostatni element, który chciałbym dziś zaprezentować to własny filtr modyfikujący wybrane pole. W tym celu spróbujemy napisać funkcję, która będzie do każdego pola body dopisywać etykietę: Tresc posta:
W tym celu do naszego kontrolera dopisujemy już ostatnie linie – a mianowicie nowy filtr.
Kod postsController.php po wszystkich dzisiejszych zmianach:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
angular.module('ourApp') .controller('PostsController', function($http,posts,$scope) { var vm = this; vm.posts = false; vm.postsfromapiservice = {}; vm.choosenPost = {}; posts.findall({}, function(data) { vm.postsfromapiservice.items = data; }); vm.mojaFunkcja = function(record){ if (vm.mojaFunkcjaOn) { return record.body.length; } else { return false; } } }).filter('tytul', function() { return function(item) { var txt = ""; txt = 'Tresc posta: ' + item; return txt; }; });; |
Jak widzimy, pod koniec skryptu, zdefiniowano nowy filtr o nazwie tytul. Ciało funkcji będącej filtrem jest trywialne, do każdego elementu przekazanego do filtru dodawana jest wartość Tresc posta. Samo wywołanie tak stworzonej struktury jest równie proste, poniżej cały now kod widoku:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<div ng-controller="PostsController as vm"> <h1>Posts</h1> Ilosc postow: <input ng-model="vm.count" /> Wyszukiwarka: <input ng-model="vm.query" /> Sortowanie <select ng-model="vm.sorting"> <option value="body">Tresc (Rosnąco)</option> <option value="id">ID (Rosnąco)</option> <option value="-body">Tresc (Malejąco)</option> <option value="-id">ID (Malejąco)</option> </select> Moja funkcja <input type="checkbox" ng-model="vm.mojaFunkcjaOn"/> <ul > <li ng-repeat="x in vm.postsfromapiservice.items | filter:vm.query | orderBy:[vm.mojaFunkcja, vm.sorting] | limitTo:vm.count" ng-class-odd="'nieparzysty'" ng-class-even="'parzysty'"> {{ x.id}} | {{x.body | uppercase | tytul}} </li> </ul> </div> |
Jak widzimy nowy kod umieszczony został w linii:
1 |
{{ x.id}} | {{x.body | uppercase | tytul}} |
Uruchomienie aplikacji ukaże wynik działania nowego filtru:
Reasumując, w tym prostym przykładzie udało nam się umieścić kilka technik filtrów dostępnych w Angularze:
- Limitowanie ilości postów (limitTo)
- Wyszukiwanie treści (filter:vm.query)
- Sortowanie po polu lub też własna funkcja sortująca (orderBy:[vm.mojaFunkcja, vm.sorting])
- Formatowanie pól, przy użyciu filtrów wbudowanych i własnych funkcji ({{x.body | uppercase | tytul}} )
Filtrowanie w Angularze to temat ciekawy i często wykorzystywany w praktyce. Warto go znać, umiejętnie korzystać, a także dostosowywać do swoich potrzeb. Jak zawsze zachęcam do testowania i zagłębienia się w zaprezentowany temat.
git: https://gitlab.com/spooky001/blog-angularjs