Zanim pojawił się AngularJS aplikacje webowe budowaliśmy najczęściej według jednego schematu.
Tworzyliśmy stronę dostępną pod konkretnym adresem URL, na której asynchronicznie (ajaxem) obsługiwaliśmy akcje pobierania i odświeżania danych.
Każda taka akcja polegała na wysłaniu żądania HTTP oraz oczekiwaniu na odpowiedź z danymi.
Po otrzymaniu odpowiedzi aktualizowaliśmy widok strony bez jej przeładowania.
Aktualizacja widoku polegała na podmianie komponentu na nowy, najczęściej za pomocą własności (lub funkcji) innerHTML.
Dużym ograniczeniem tego rozwiązania było to, że tak naprawdę mieliśmy do dyspozycji jeden podstawowy widok, w którym wymienialiśmy jedynie poszczególne klocki.
Natomiast wiadomo, że aplikacja webowa wymaga często wielu różnych widoków reprezentowanych przez całe strony, a nie tylko ich części.
W takiej sytuacji mieliśmy zwykle dwa wyjścia.
Mogliśmy albo tworzyć osobne strony, które były pobierane osobnymi requestami i leżały pod różnymi adresami na serwerze (mało wydajne),
albo korzystać z pojawiających się bibliotek obsługujących routing po stronie samego Javascriptu, co wymagało jednak dodatkowej wiedzy i zaangażowania.
Stany w aplikacji AngularJS
W momencie gdy pojawił się AngularJS szybko popularne stało się pojęcie stanu aplikacji. Definiowanie stanów z różnymi widokami stworzyło nam możliwość zarządzania
stroną w ramach jednego adresu URL na serwerze, ale pod różnymi URL-ami widzianymi w przeglądarce przez użytkownika.
Przykładowo jeśli nasza aplikacja StartAPPa jest dostępna pod adresem:
www.javappa.com/aplikacja
to pomimo, że przełączając się pomiędzy kolejnymi widokami widzimy regularnie zmieniający się URL w przeglądarce:
www.javappa.com/application/appa/admin
www.javappa.com/application/appa/create
www.javappa.com/application/appa/items,
to i tak cały czas znajdujemy się na stronie załadowanej RAZ, na samym początku z adresu:
www.javappa.com/aplikacja
Przechodząc pomiędzy widokami mamy wrażenie jakbyśmy za każdym razem zmieniali stronę (ze względu na zmieniający się URL),
mimo że tak naprawdę nie pobieramy nowych stron z serwera i cały czas pozostajemy na tej jednej załadowanej na starcie.
To właśnie strona pod tym adresem jest odpowiedzialna za trzymanie odpowiedniej struktury HTML oraz załadowanie skryptów JS i plików ze stylami.
Każde przejście użykownika do innego widoku inicjuje jedynie asynchroniczne pobranie danych potrzebnych dla tego widoku, jak również
dostarcza wymagane komponenty do przechowywania/prezentacji tych danych. Dzięki temu, że nie pobieramy wtedy z serwera skryptów JS i plików css,
jak również nie musimy pobierać całego szablonu strony. Przechodzenie między kolejnymi widokami staje się bardzo szybkie i sprawia wrażenie jakby
nie wymagało w ogóle połączenia internetowego (oczywiście o ile nie pobieramy bardzo dużych zbiorów danych).
Dostawca stanu ($stateProvider)
Tak jak pisaliśmy wcześniej, każdy z widoków wraz z przypisanym do niego URL-em jest nazywany stanem. Jeśli chcemy stworzyć aplikację z wieloma stanami
potrzebujemy dodatkowo wprowadzić odpowiedni mechanizm zarządzający. Takim właśnie mechanizmem jest $stateProvider.
Należy jednak pamiętać, że
$stateProvider nie jest providerem wbudowanym w AngularJS. Aby z niego korzystać
musimy ściągnąć i podpiąć do naszej aplikacji dodatkowy moduł zewnętrzny
ui-router:
Następnie w sekcji
config aplikacji wstrzykujemy naszego dostawcę stanu wraz z dostawcą routingu URL
$urlRouterProvider.
Od teraz możemy przystąpić już do definiowania
stanów aplikacji:
Widzimy, że dla każdego ze stanów określone zostały parametry:
-
url - URL wstawiany w przeglądarce, w momencie gdy nakazujemy frameworkowi przekierowanie do danego stanu
-
templateUrl - ścieżka do pliku, który zawiera kod HTML naszego widoku
-
controller - kontroler obsługujący widok (obsługuje zdarzenia, ustawia i pobiera dane z widoku itp.)
Przejście do stanu
No dobrze. Mamy zatem stany, a także określone powiązania do konkretnych widoków. Pojawia się teraz pytanie, w jaki sposób możemy przekierować użytkownika do danego widoku,
gdy użytkownik ten kliknie w wybrany link na stronie? Otóż, możemy to wykonać na kilka sposobów:
- Funkcja - $state.go([[NAZWA_STANU]])
Jeśli mamy do czynienia z pojedynczym linkiem bądź przyciskiem, wówczas używamy dyrektywy ng-click:
oraz zwyczajnie definiujemy w kontrolerze kod, który uruchamia odpowiednią funkcję: $state.go([[NAZWA_STANU]]):
Oczywiście $state musi być najpierw wstrzyknięty do naszego kontrolera.
- Dyrektywa ui-sref
W przypadku gdy mamy w aplikacji grupę linków, na przykład w postaci menu, możemy też użyć dyrektywy ui-sref.
Za przykład niech posłuży nam fragment kodu tworzący menu aplikacji StartAPPa. Przedstawia on trzy linki, które wiążemy ze stanami
(admin, create, items), podając ich nazwy w dyrektywie ui-sref:
Nie musimy wywoływać żadnych dodatkowych funkcji z poziomu kontrolera. Dyrektywa ta sprawdza się doskonale gdy
linki służą nam tylko do przełączania widoków, bez dokonywania dodatkowych operacji (np. pobierania danych).
Dyrektywa ui-view
W tym miejscu od razu trzeba wspomnieć, że dyrektywa
ui-view jest po części kontynuacją poprzedniego paragrafu, gdyż
podobnie jak
ui-sref, ona też pozwala na podanie nazwy widoku, który chcemy pokazać. Podstawowa różnica polega na tym, że
dyrektywa ta nie przeznaczona do użytku z linkami czy przyciskami, tylko działa w momencie załadowania kodu strony.
Dyrektywę podajemy jako atrybut tagu
div:
Dyrektywa umożliwia podanie również nazwy widoku, co pozwala na wprowadzenie widoku domyślnego:
Jednak najważniejsze jest to, że gdy przełączamy się między widokami aplikacji
przy pomocy
$state.go lub
ui-sref, to widok uzyskiwany ze
$stateProvidera będzie wstawiony w kodzie HTML
zawsze w
miejscu położenia diva z tą dyrektywą:
Rekomendacja
Wszystkie opisane powyżej elementy stanowią niezbędną wiedzę do "sterowania ruchem" w tworzonej przez nas aplikacji.
Nie wyczerpaliśmy jednak tego tematu do końca, więc zapraszamy również do sekcji linków dostępnych na dole strony.
Znajduje się tam odnośnik do githuba projektu ui-router, gdzie znajdziecie kilka dodatkowych informacji.
Z ciekawszych zagadnień warto zwrócić uwagę na opis przedstawiający sposób przekazywania parametrów do stanu.
Używamy w StartAPPa
Zgodnie z tym co już wielokrotnie wspominaliśmy, każdy moduł aplikacji StartAPPa jest przekształcany specjalnie dla Was w niezależnie działającą aplikację.
Stąd też ściągnięty projekt zawiera charakterystyczną strukturę plików, zgodną z opisem z rozdziału:
Projekt startowy Spring Boot + AngularJS.
Po pobraniu projektu znajdziecie tam więc między innymi plik
router.js, a w nim konfigurację stanów dostarczoną przez
$stateProvidera.
Większość modułów, ze względu na swoją prostą konstrukcję posiada niewielką liczebność obsługiwanych stanów. "Najbogatszy" w tym temacie jest
projekt w kursie
Login & Reset, którego fragment przedstawiliśmy w bieżącym rozdziale
(opisując
$stateProvidera). Ze względu na swoją specyfikę (wykonywanie przekierowań do widoków logowania, resetowania hasła, ustawienia nowego hasła itp.)
definiuje on i zarządza on aż siedmioma różnymi stanami.
Linki:
https://ui-router.github.io/ng1/docs/latest/modules/directives.html