ANGULAR 2 BIDRECTIONAL SERVICE – komunikacja komponentów poprzez serwis

Najczęściej nasze komponenty komunikują się przy użyciu dekoratorów Input() oraz Output(). Niestety niesie to za sobą pewne ograniczenia. Zarówno Input oraz Output, służą do komunikacji komponentów w bezpośredniej relacji rodzic-dziecko. Co jeśli chcemy komunikować komponenty niezależnie od relacji?

BIDIRECTIONAL SERVICE

Pomoże nam w tym dwukierunkowy serwis, który będzie współdzielony przez rodzic-komponent oraz jego dzieci.

Zasięg instancji serwisu dotyczy tylko danego drzewa komponentów, wszystkie komponenty, które nie należą do danego drzewa, nie mają dostępu do serwisu.

Na potrzeby artykułu, załączam Live Example.

LIVE EXAMPLE

Jakie wątki poruszymy w tym artykule?

  • napiszemy bi-directional service, który będzie zawierał metody do komunikacji naszych komponentów
  • wyślemy dane do komponentu trzy levele niżej w drzewie komponentów
  • komponent najniżej zagnieżdżony skomunikuje się z komponentem-rodzicem

W przedstawieniu graficznym, wykonamy następujące interakcje:

TWORZYMY SERWIS

Jeśli zapoznałeś się już ze plikami z live example na plunkerze, to skupimy się teraz na naszym dwu-kierunkowym serwisie (user-shared.service.ts):

Rozłóżmy kod na czynniki:

Subject jest klasą, która pochodzi z biblioteki RxJs, która implementuje reaktywne programowanie. Jest to skomplikowany i mocno rozbudowany koncept, stąd na potrzeby tego artykułu, nie będę wdawać się w szczegóły RxJs.  W przypadku zainteresowania tematem, załączam linka do Subject w dokumentacji RxJs.

Zatem krótko o Subject:

  • Subject jest strumieniem, jest to jednocześnie Observable oraz Observer
  • posiada między innymi metodę next(value), która powoduje emisję przekazanej wartości.

Publiczne pole userContent$ posłuży nam do odbioru informacji w komponentach. Po subskrypcji do tego pola, będziemy mieli dostęp do danych.

Metoda shareUser posłuży nam do emisji danych usera z poziomu UserDetailComponent.

Analogicznie z messageSource, które wykorzystamy do powiadomienia UserDetailComponent z poziomu ChildChildChildComponent.

WYSYŁAMY DANE DO KOMPONENTU 3 POZIOMY NIŻEJ

Serwis gotowy, więc czas przekazać dane Usera z komponentu UserDetailComponent do ChildChildChildComponent. W pliku user-detail.component.ts, zaczynamy od wstrzyknięcia naszego serwisu UserSharedService w konstruktorze oraz dodania go do providers.

W powyższym kodzie, odebraliśmy konkretnego usera, metoda subscribe udostępnia nam jego dane. Podepniemy się w tym miejscu z wywołaniem metody shareUser naszego dwu-kierunkowego serwisu UserSharedService, który wyemituje przekazane dane. Pozostaje nam tylko teraz wykonać subskrypcję do $userContent, który umożliwi nam dostęp do wyemitowanych danych.

Przechodzimy do ChildChildChildComponent (child-child-child.component.ts)

Zaczynamy od stworzenia subscription, które pochodzi z biblioteki RxJs. Subscription to obiekt, który reprezentuje zasoby w postaci Observables. Ma jedną bardzo ważną metodę – unsubscribe(), która umożliwia nam się pozbycia zasobów trzymanych w subscription, służy to przede wszystkim zapobieganiu wyciekom pamięci.

Generalnie w naszym przykładzie użycie subscription i metoda unsubscribe() nie ma znaczenia, ponieważ cykl życia ChildChildChildComponent jest identyczny jak UserComponent, także wycieki pamięci nie mają prawa bytu. Jednak w bardziej złożonych aplikacjach, warto pamiętać o użyciu unsubscribe(). Użyłem subscription wyłącznie demonstracyjnie.

Powyższy kod, zapewnił nam odebranie w ChildChildChildComponent danych usera z UserComponent. To jest idea dwukierunkowego serwisu w pigułce. W analogiczny sposób, ChildChildChildComponent da znać UserComponent, że odebrał dane, emitując wiadomość poprzez metodę tellSomethingToParent(), która zostanie wywołana na kliknięcie buttona.

PODSUMOWANIE

Idea bidirectional service jest bardzo przydatna, zwłaszcza jak chcemy wysyłać dane między komponentami, które nie są między sobą bezpośrednio połączone. Pamiętaj, że dodanie takiego serwisu do providers danego komponentu, tworzy Ci nową instancję tego serwisu. Jeśli planujesz użyć takiego serwisu, np. do wystawienia danych zalogowanego użytkownika w całej aplikacji, musisz ten serwis dodać do providers w głównym ngModule aplikacji, dzięki temu nasz serwis będzie singletonem (jedna instancja serwisu na całą aplikację).

5 Comments

    • Tomasz Nastały

      EventEmitter dziedziczy po Subject, więc mogłoby się wydawać, że też będzie OK.
      Tym niemniej Angular Team, zaleza używanie EventEmittera wyłącznie z @Output w dyrektywach i komponentach.

  1. Pingback: RxJS w Angular – co wypada wiedzieć – Angular.love

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *