AgendaEditor: wymiana danych pomiędzy zakładkami poprzez serwisy

W poprzednim wpisie poznaliśmy teorię na temat serwisów i proste przykłady. Teraz możemy je zastosować w praktyce w naszej aplikacji, aby zachowywać dane podczas przechodzenia pomiędzy zakładkami. W przyszłości będzie nam to potrzebne, aby dodać różne funkcjonalności na różnych zakładkach (np. import danych). W tym wpisie dodamy tylko zakładkę z wynikiem tekstowym ankiety, aby przetestować utworzony serwis.

Tworzenie serwisu

Na nasze potrzeby wybraliśmy serwis typu Service (wygodnie się go używa poprzez this, a początkowa konfiguracja dostępna w Provider nie jest nam potrzebna).

Utwórzmy nowy folder, w którym będziemy trzymali nasze serwisy: services. Tam plik o nazwie agenda.js, w którym będzie nasz serwis. Przeniesiemy tam funkcjonalność z kontrolera z pliku home/home.js.

Problem będziemy mieli ze zmienną startTime, bo jest ona typu prymitywnego (lista list i funkcja myResult będzie działać) i nie będzie działać bindowanie. Rozwiązania są dwa.

Rozwiązanie 1 – zmienna opakowana w obiekt

Nie ma referencji? To opakujmy zmienną w obiekt o nazwie model, aby mieć się do czego odwołać. Jeśli aplikacja będzie się rozrastała, będzie można tam dorzucić dodatkowe zmienne (ale obecnie jest to trochę brzydkie rozwiązanie).

W serwisie będzie to wyglądało tak:

W kontrolerze będziemy musieli przypisać obiekt do $scope:

A w widoku odwołać się do konkretnej zmiennej:

W kontrolerze oczywiście musimy przypisać wszystkie zmienne i funkcje do $scope, aby mieć do nich dostęp w widoku:

Rozwiązanie 2 – przypisanie całego serwisu do $scope

Jest jeszcze drugie rozwiązanie tego problemu. Ogólnie dobra praktyką w AngularJS przy bindowanie jest „zawsze używaj kropek” (bo oznacza to, że będzie referencja). Dlatego opakowaliśmy zmienną startTime w obiekt model, aby móc się odwołać do niego za pomocą kropki: model.startTime.

Jeśli jednak nie opakujemy zmiennej, to skąd wziąć tę kropkę? Przypiszmy cały serwis do $scope. Wtedy będziemy mieli: naszSerwis.startTime.

Czyli w serwisie mamy ładnie zmienną:

A w kontrolerze przypisujemy cały serwis do $scope:

Dzięki temu nie będziemy musieli tez pojedynczo przypisywać wszystkich zmiennych i funkcji z serwisu.

Jednak teraz w widoku musimy się odwołać do serwisu, aby uzyskać dostęp do danej zmiennej:

Na pierwszy rzut oka to wygląda gorzej, ale jeśli się zastanowić, to jest lepiej, bo dane są usystematyzowane (godzina rozpoczęcia wydarzenia powinna być w „pojemniku” związanym z agendą). Jeśli mielibyśmy kilka serwisów, byłoby to dużo bardziej czytelne niż poprzednie rozwiązanie (i mniej pracy oraz błędów z przepisywaniem wszystkich zmiennych – nie było też konfliktów nazw).

Kod serwisu (plik agenda.js) wygląda następująco:

Kontroler (plik home.js) wygląda teraz tak:

Jak widzimy pozostała tu funkcja dodawania kolejnego pustego pola na liście. Nie zaśmiecaliśmy nią serwisu, bo nie dotyczy bezpośrednio przetwarzanych danych, a tylko widoku w danej zakładce. Dlatego idealnym miejscem na nią jest ten kontroler.

Zaś w widoku musimy odwoływać się do zmiennych za pomocą agenda.nazwaDanePola:

Teraz nasze dane po wpisaniu będą zapamiętywane w serwisie i po przełączeniu się na inną zakładkę nie będą tracone.

Dodatkowa zakładka z wynikiem agendy

Możemy teraz bardzo łatwo skorzystać z już utworzonego serwisu. Dodajmy zakładkę, w której będzie umieszczony wynik agendy w formie tekstowej (czyli to co już mamy, ale na osobnej zakładce).

Tworzymy nowy folder (zgodnie ze strukturą „folder dla funkcjonalności/podstrony”result.

Umieszczamy w nim plik result.js z kontrolerem i konfiguracją routingu dla danej zakładki:

Dodajemy też plik result.html z widokiem:

Oczywiście musimy dodać w pliku index.html plik z kontrolerem i zakładkę w menu:

W ten sposób szybko utworzyliśmy nową zakładkę z funkcjonalnością korzystającą z naszego serwisu.

Podgląd działania aplikacji

Otwarcie w nowej oknie.

2 responses on “AgendaEditor: wymiana danych pomiędzy zakładkami poprzez serwisy

Dodaj komentarz

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