Kontynuujemy temat z poprzedniego rozdziału i tym samym pozostajemy w świecie usług. Usługa typu provider, o której chcemy napisać jest mocno powiązana
z usługami typu factory i service.
Wszystkie te trzy typy mają jedną cechę wspólną. Okazuje się, że
tak samo jak service wywołuje factory, tak samo factory wywołuje dalej providera!
Provider ten jest źródłem dla pozostałych usług w Angularze.
Natomiast mimo tego, że pod spodem każdej fabryki znajduje się provider, to tutaj w przeciwieństwie do relacji typu service - factory,
nie można powiedzieć, że provider znajduje się z nimi w relacji równoważnej.
Co prawda jest on odpowiedzialny za dostarczenie obiektu usługi, niemniej nie posiada on dokładnie takich samych cech jak service czy factory.
Podstawowa różnica polega na tym, że
do providera nie możemy wstrzykiwać zależności w postaci serwisów i fabryk.
Tak więc nie wstrzykniemy do niego ani angularowego serwisu
$http czy
$q,
ani też żadnej innej usługi stworzonej przez nas w aplikacji.
Dodatkowo, podstawowym przeznaczeniem providera jest dostarczanie obiektów usługowych działających w ramach całej aplikacji i ładowanych
od razu podczas jej startu.
Ze względu na wspomniane właściwości
provider doskonale nadaje się do konfigurowania aplikacji w ramach metody config (w przeciwieństwie do fabryk i serwisów - ich nie możemy podpiąć za pomocą tej metody).
Zobaczmy teraz jak użycie providera wygląda w praktyce.
Provider w akcji
Tworzymy providera dostarczającego informacje o naszej aplikacji (numer wersji, data releasu) i podpinamy go do modułu aplikacji.
To co jest charakterystyczne dla providerów w AngularJS, to konstrukcja opierająca się na wykorzystaniu własności
$get.
Własności tej przypisujemy funkcję
fabryki opakowującej de facto funkcję serwisu, co w efekcie dopełnia klamrą model usług:
provider -
factory -
service.
Jeśli chcemy to możemy użyć providera w taki sposób aby zarówno wykorzystywać jego możliwości konfiguracyjne,
jak i
używać go razem z fabryką, która będzie posiadać metody służące przetwarzaniu danych. Można wykorzystać takie rozwiązanie
jeśli na przykład będziemy chcieli stworzyć generyczną usługę przygotowaną do użycia w różnych aplikacjach. Na poniższym przykładzie pokazujemy
podobny kod usługi, jak ten który opisujemy w ramach rozdziału dotyczącego fabryki i serwisu, jednak tutaj przyjmujemy założenie, że będzie on użyteczny globalnie
(nie będzie się opierał o model jednej konkretnej aplikacji).
Spostrzegawcze osoby z pewnością zauważyły, że nazwa providera wyjątkowo została pozbawiona przez nas suffixu
Provider.
Nie jest to przypadek. Celowo użyliśmy takiej nazwy, ponieważ
w bloku konfiguracyjnym do nazwy wstrzykniętego providera
i tak zostanie automatycznie dołączone słowo Provider.
Ustawiamy zatem numer wersji oraz datę releasu w ramach funkcji
config. Jak widać zgodnie z tym co napisaliśmy w poprzednim
akapicie, mimo że nazwę providera określiliśmy jako
ApplicationInfo, to do naszego bloku konfiguracyjnego
wstrzykujemy go jako
ApplicationInfoProvider:
Rozwiązanie z automatycznym doklejaniem suffixu nie było by wcale złe gdyby nie fakt, że teraz jeśli będziemy chcieli użyć naszego providera aby odczytać
skonfigurowane wartości w którymś z naszych kontrolerów w aplikacji, to będziemy to robić wstrzykując go za pomocą
nazwy źródłowej, a więc
ApplicationInfo!
Na koniec jeszcze jedna ważna sprawa, o której należy wspomnieć w kontekście dostawców. Funkcje, które są przypisane bezpośrednio do
obiektu providera (w naszym przykładzie są to:
setVersion oraz
setReleaseDate),
są widoczne tylko z poziomu bloku
config. Nie dostaniemy się do nich z poziomu kontrolera.
Natomiast funkcje fabryki i serwisu (zawartych w providerze) odwrotnie - nie są dostępne z poziomu funkcji
config. Możemy dostać się do nich
standardowo z poziomu kontrolera (np. po to by odczytać wartość ustawioną w konfiguracji).
Nasza rekomendacja
Mimo, że teoretycznie jest to możliwe (poprzez implementowanie kodu fabryki w providerze), to jednak nie jest zalecane aby providera wykorzystywać jako podstawowy typ dla usług budowanych
wokół modelu domenowego aplikacji. Pownien on nam służyć jako dostawca usług niezależnych od modelu biznesowego konkretnej aplikacji, tak aby był możliwy do przeniesienia do innych aplikacji.
Dodatkowo, dzięki odseparowaniu części konfiguracyjnej od wykonawczej, może być bardzo pomocny we wdrażaniu różnych wersji konfiguracji dla tej samej usługi.
Używamy w StartAPPa
Aplikacja ze względu na szereg ustawień konfiguracyjnych posiada specjalnie zdefiniowanego providera z wieloma elementami konfiguracyjnymi.
W kursach stosujemy głównie gotowe providery, takie jak $growlProvider czy $stateProvider, dlatego też zamieściliśmy
w bieżącym rozdziale cały przykład customowego providera, który możecie w łatwy sposób wpiąć do swoich aplikacji (dodając kod Javascript do app.js oraz kontroler o nazwie StartappaCtrl do pliku index.html).
Linki
https://docs.angularjs.org/guide/providers#provider-recipe
https://docs.angularjs.org/api/auto/service/$provide