Wymiana danych pomiędzy kontrolerami w AngularJS czyli serwisy

W aplikacji AngularJS dane przetwarzane są w kontrolerach. Jeśli coś wpiszemy np. w formularzu w jednym widoku (na jednej podstronie), dane dostępne są w kontrolerze przypisanym do niego.

Czasem jednak zachodzi potrzeba, aby dane były dostępne na wielu zakładach (czyli w wielu kontrolerach i widokach). Jak widzimy w naszej aplikacji, jeśli na głównej zakładce w formularzu wpiszemy dane, a następnie przełączymy się na inną i powrócimy, to zobaczymy, że dane z formularza zostały utracone (były w tym jednym widoku i po przełączeniu on się przeładował).

Jak sobie z tym poradzić? Moglibyśmy za każdym razem zapisywać dane do bazy danych, a po powrocie na daną zakładkę przywracać je. Tylko rodzi to kilka problemów. Kiedy zapisywać dane (po kliknięciu na inną zakładkę? po każdorazowym naciśnięciu klawisza)? Po co obciążać serwer? Dane każdorazowo musiałyby być wczytywane, co spowalniałoby działania aplikacji. Nie jest to dobre rozwiązanie w tym przypadku. Dane powinny być przechowywane po stronie klienta.

Serwisy w AngularJS

AngularJS udostępnia nam gotowy mechanizm, aby rozwiązać ten problem: serwisy. Jest to dodatkowa warstwa logiki aplikacji. Na początku tworzony jest obiekt, w którym będą przechowywane i przetwarzane dane (dostępne w całej aplikacji), a w kontrolerach i widokach będziemy się do niego tylko odwoływać.

Są trzy rodzaje serwisów:

  • Factory – zwracamy obiekt z polami (zmienne lub funkcje), użycie return,
  • Service – przypisanie zmiennych lub funkcji do pól obiektu za pomocą słowa kluczowego this,
  • Provider – serwis, który można skonfigurować w sekcji config, zwracanie obiektu poprzez funkcję $get.

W tutorialu, do którego wcześniej linkowałem, są opisane wszystkie trzy serwisy: Factory vs Service vs Provider. Również w książce AngularJS. Pierwsze kroki, w rozdziale Dependency Injection — wstrzykiwanie zależności: DI w praktyce (str. 37) są opisane wszystkie rodzaje serwisów.

Który wybrać? Factory jest najprostsze. Jednak konieczność używania return jest trochę niewygodne (chociaż kto co lubi). Według mnie lepiej użyć Service, gdyż dostęp do pól obiektu poprzez słówko this jest wygodniejszy (tylko przypisujemy tam wartości i jest już dostępne, nie musimy nic zwracać). Jeśli mamy potrzebę konfiguracji serwisu przed załadowaniem aplikacji, wybierzmy Provider (w prostych aplikacjach zazwyczaj nie ma takiej potrzeby). Jednak jego użycie jest trochę bardziej skomplikowane.

Dlatego na nasze potrzeby wybierzmy serwis typu Service.

Serwis typu Service

Ogólna składnia wygląda tak:

Polami mogą być zmienne (również, a nawet przede wszystkim obiekty) oraz funkcje. Należy pamiętać, że jeśli polem będzie zmienna typu prymitywnego (np. napis, liczba), to będziemy mogli z niej korzystać, jednak bindowanie w AngularJS nie będzie działało prawidłowo. Dlatego polami serwisu muszą być obiekty (A dopiero w nim prymitywne zmienne), żeby można było zbindować referencję.

W naszym przykładowym serwisie będziemy mieli obiekt model z jednym polem myValue (pól może być więcej) oraz funkcję myText.

Utworzymy dwa kontrolery, żeby sprawdzić czy wymiana działa oraz dwa pola input, aby sprawdzić czy prawidłowo działa bindowanie:

Jak widzimy, aby skorzystać z naszego serwisu, wystarczy go wstrzyknąć (umieścić nazwę serwisu w funkcji kontrolera). Jest to tzw. DI (Dependency Injection czyli wstrzykiwanie zależności). Chcemy z danych z serwisu skorzystać w widoku, więc musimy umieścić je w $scope poprzez kontroler.

Podczas wpisywania danych w pola tekstowe, informacje powinny być przenoszone pomiędzy kontrolerami (czyli przepisywane do drugiego pola) oraz funkcja powinna być obliczana na bieżąco (obok dopisywanie słowa Hello).

Oczywiście jest to tylko przykład. Oba kontrolery zostały umieszczone na jednej podstronie (więc aby uzyskać ten sam efekt, można by trzymać wszystko w jednym kontrolerze). Jednak ta wiedza przyda nam się na przyszłość. Nic nie stoi na przeszkodzie, aby teraz kontrolery rozdzielić na dwie podstrony i wspóldzielić pomiędzy nimi dane poprzez serwis.

Serwis typu Factory

Pokażę jeszcze rozwiązanie tego samego zadania z wykorzystaniem serwisu typu Factory. Według mnie jest mniej wygodne, ale dosyć często używane, więc warto z nim się zaznajomić.

Kontrolery i widoki zostają identyczne. Zmienia się tylko definicja serwisu.

Ogólna składnia wygląda tak (tworzymy pole i potem je zwracamy):

Lub szybciej tak (od razu zwracamy pole):

W naszym serwisie będzie to wyglądało w ten sposób:

I działający przykład:

Serwis typu Provider

Została nam jeszcze najtrudniejsza wersja serwisu czyli Provider. Ogólna jego składnia wygląda tak:

Widzimy, że podobnie zwraca się pola jak w Factory. Jednak tu musimy dodatkowo skorzystać z funkcji $get. Nie jest to zbyt wygodne, ale jeśli chcemy mieć serwis, który będziemy mogli skonfigurować przed uruchomieniem aplikacji, będziemy musieli skorzystać z tej wersji (Provider).

Czyli w naszym przykładzie będzie to wyglądać tak (sama definicja serwisu Provider, bez jego konfiguracji):

I przykład działania:

2 responses on “Wymiana danych pomiędzy kontrolerami w AngularJS czyli serwisy

Skomentuj Domnik Anuluj pisanie odpowiedzi

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *