Angular - tworzenie serwisów i wstrzykiwanie zależności

Stronę tą wyświetlono już: 13 razy

Wstęp

Zgodnie z zaleceniami twórców Angulara komponenty powinny przechowywać logikę związaną z wyświetlaniem widoku, zaś serwisy przechowywać niezbędne dla tego widoku dane. Przy małych komponentach, które spełniają zdanie kontrolki nie ma sensu wykorzystywać serwisu, ale przy dużych komponentach taka potrzeba już zachodzi. Ważne jest, aby wiedzieć, że obiekty serwisu domyślnie są obsługiwane według wzorca singleton co oznacza, że tak na prawdę pierwsze wywołanie konstruktora serwisu powoduje utworzenie jego obiektu a dalsze próby utworzenia nowych serwisów kończą się zwróceniem instancji wcześniej utworzonego obiektu serwisu. Mechanizm ten jest przydatny, gdy wiele takich samych komponentów ma dzielić te same dane. Problem powstaje, gdy każdy komponent powinien mieć własne dane a więc i tworzyć własną instancję serwisu, ale ten problem można rozwiązać dość szybko i łatwo o czym postaram się napisać na łamach tej strony.

Tworzenie pierwszego serwisu

Jak już wcześniej pisałem gdzieś na podstronach tego działu możliwe jest wygenerowanie pliku serwisu za pomocą następującego polecenia:

ng g s Data

które to spowoduje powstanie pliku o nazwie data.service.ts i drugiego data.service.spec.ts, którym w tej chwili zajmować się nie będę. Oto jak wygląda podstawowa wygenerowana klasa serwisu:

Listing 1
  1. import { Injectable } from '@angular/core';
  2. @Injectable({
  3. providedIn: 'root'
  4. })
  5. export class DataService {
  6. constructor() { }
  7. }

Jak widać nic ciekawego, no może poza dekoratorem Injectable, który umożliwia wykorzystania mechanizmu wstrzykiwania zależności. Mechanizm ten pozwala już na poziomie konstruktora klasy komponentu wstrzyknięcie zmiennej serwisu bez konieczności podawania jej parametrów (których w tej chwili brak) a nawet i jawnego tworzenia instancji tejże klasy.

Parametr providedIn dekoratora Injectable powoduje, że możliwe będzie jedynie operowanie na pojedynczej instancji serwisu, który w tym przypadku będzie musiał być wstrzykiwany. Gdyby usunąć ten parametr i utworzyć następujący serwis:

Listing 2
  1. import { Injectable } from '@angular/core';
  2. @Injectable()
  3. export class DataService {
  4. data1: string = 'some data';
  5. data2: string = 'some data';
  6. constructor() { }
  7. }

Wtedy to w kodzie jakiegoś komponentu można by utworzyć dwie oddzielne instancje serwisu:

Listing 3
  1. let data: DataService = new DataService();
  2. let data2: DataService = new DataService();
  3. data.data1 = 'NEW STRING';
  4. console.log('data', data);
  5. console.log('data2', data2);

Wynik działania powyższego kodu w konsoli przeglądarki:

data 
Object { data1: "NEW STRING", data2: "some data" }
data2 
Object { data1: "some data", data2: "some data" }

Wstrzykiwanie zależności

Wstrzykiwanie serwisu do komponentu wygląda następująco:

Listing 4
  1. constructor(private dataservice: DataService) {}

Od tej pory można korzystać z zmiennej dataservice będącej instancją klasy DataService. Wstrzykiwana zależność powinna mieć określony warunek dostępu do jej danych. Jeżeli chcesz, aby możliwe było wykorzystanie danych serwisu w kodzie HTML wystarczy podać zamiast private słowo kluczowe public

Zaletą tego rozwiązania jest to, że gdyby serwis zmienił parametry, które też muszą być serwisami udekorowanymi dekoratorem Injectable to nie będzie konieczne w każdym komponencie poprawianie parametrów, jakie do niego są przekazywane. Cały mechanizm tworzenia instancji jest realizowany przez Angular-a.

Komentarze