P-Programowanie

Scope i wyrażenia

Ostatania modyfikacja: 19 kwietnia 2017, kategoria: Kurs angular

Zrozumienie tego artykułu jest kluczowe aby móc tworzyć aplikacje w AngularJS. Do tej pory powinieneś wiedzieć czym jest Angular, umieć utworzyć moduł główny aplikacji i podpiąć do niego kontroler. Zdefiniowany przez nas moduł oraz kontroler zostają załadowane do pamięci w fazie ładowania. Następnie w fazie kompilacji AngularJS analizuje statyczne drzewo DOM dokumentu zbudowane ze znaczników HTML. W momencie natrafienia na dyrektywy ng-application oraz ng-controller zostaje utworzony nowy $scope.

Czym jest $scope

W większości języków programowania możemy definiować własne zasięgi zmiennych, w których są one widoczne. W C++ każda funkcja posiada swój własny zasięg ograniczony przez nawiasy klamrowe. Nic nie stoi na przeszkodzie aby w środku funkcji zagnieździć kolejne nawiasy klamrowe definiujące nowy zakres widoczności.

$scope w AngularJS jest niczym innym jak zasięgiem widoczności danego kontrolera i tworzy on warstwę widok-model wzorca MVVM. Każdy kontroler posiada swój unikalny $scope do którego przypięte są funkcje oraz zmienne widoczne w warstwie widoku. $scope jest jedynym elementem, który jest w stanie wystawić dane dla widoku i komunikować się z widokiem.

W czystym JavaScripcie zasięgi zmiennych tworzone były poprzez funkcje anonimowe, w AngularJS posiadamy kontrolery, które także są funkcjami.

$scope zostaje utworzony automatycznie dla każdego kontrolera, który zostanie zainicjalizowany dyrektywą ng-controller (lecz nie tylko o czym później). Oprócz tego, podczas inicjalizacji aplikacji za pomocą dyrektywy ng-app zostaje utworzony tzw. $rootScope, a więc zasięg bazowy dla wszystkich innych.

W przypadku zagnieżdżonych kontrolerów zasięgi także zostają zagnieżdżone. Każdy $scope posiada referencję do dziecka child-scope oraz do rodzica parent-scope. Rodzicem nadrzętnym jest $rootScope. Nie jest to informacja, która może Ci się przydać na początku kursu, jednak warto o takim fakcie wiedzieć. Rozwieje to Twoje wątpliwości szczególnie podczas przeglądania $scope za pomocą wtyczki ngInspector.

Dwustronne bindowanie danych

Potęgą frameworków JavaScriptowych jest niezaprzeczalnie mechanizm dwustronnego bindowania danych two-way data binding. Jest to element obiektu $scope i zapewnia dynamiczne odświeżanie danych pomiędzy widokiem a view-modelem (czy też upraszczając kontrolerem).

Każdy kto pisał cokolwiek w JavaScript lub jego młodszym bracie jQuery wie jak uciążliwe jest wymienianie danych pomiędzy elementami HTML a skryptem. W AngularJS nie trzeba się o to martwić.

Wyrażenia

Zanim przetestujemy mechanizm dwustronnego bindowania danych trzeba dowiedzieć się czym są wyrażenia. Wyrażenia w AngularJS służą do przekazywania danych pomiędzy kontrolerem a widokiem (w jedną stronę!):

Istnieją dwie metody na przekazanie wyrażenia do widoku:

  • Przekazanie wyrażenia za pomocą nawiasów klamrowych np. {{wyrażenie}}
  • Przekazanie wyrażenia za pomocą wbudowanej dyrektywy np. ng-bind="wyrażenie"

Wyrażenia w AngularJS są takie same jak w JavaScript, mogą zawierać zmienne, literały oraz operatory. W celu przetestowania wyrażeń proponuję podpiąć do $scope zmienną o dowolnej treści. Przykładowo utworzę atrybut imie o wartości „Karol”. Definiowanie atrybutów i funkcji obywa się tak samo jak w przypadku JavaScript.:

Po otworzeniu powyższego kodu w przeglądarce Chrome przekonasz się, że zmienne zostały wyświetlone w poprawny sposób. Nawiasy klamrowe można zastąpić dyrektywą ng-bind:

Wynik dwóch powyższych linijek będzie ten sam. Jedyna różnica w przypadku posługiwania się dyrektywą jest to, że musi być ona osadzona w jakimś znaczniku HTML. Z tego powodu konieczne było utworzenie dodatkowego spana wewnątrz akapitu aby można było zbindować do niego wartość zmiennej. Z tego powodu bardziej popularne i wygodniejsze są nawiasy klamrowe.

Spójrzmy jak wygląda struktura zakresów podglądając je za pomocą wtyczki ngInspector:

Wyraźnie widać moduł, podpięty do niego $rootScope oraz jego dziecko czyli $scope naszego kontrolera. Uwaga, aby dodatek ngInspector działał plik jaki badamy musi być serwowany przez serwer np. przez serwer lokalny. Odwołując się do pliku za pomocą ścieżki file:// wtyczka nie uruchomi się. Szybki darmowy serwer HTTP jest wbudowany np. w npm (http-server). Można użyć też XAMPA lub innych podobnych.

Modele

Użycie modelu dostarcza nam 100% prawdziwego mechanizmu dwustronnego bindowania, z którego słyną frameworki JavaScriptowe. W przypadku modelu bindowanie odbywa się w dwie strony, a więc zmiany które zajdą w formularzu są widocznie w kontrolerze oraz na odwrót:

Modele można podpinać wyłącznie do kontrolek HTMLowych czyli np. do elementów input. Jedyną możliwością podpięcia modelu jest użycie wbudowanej dyrektywy ng-model. Przykładowo:

Powyższy kod podpina do pola tekstowego model $scope.imie. Po uruchomieniu kodu wartość zmiennej zostanie automatycznie zbindowana do widoku.

Pełny przykład bindowania danych

Sprawdźmy teraz, dlaczego AngularJS jest tak fajny jak o nim mówią. Poznaliśmy podstawowe mechanizmu umożliwiające bindowania danych, spróbujmy je ze sobą połączyć. W tym celu zdefiniujmy model dla zmiennej imie oraz nazwisko a następnie za pomocą wyrażenia wyświetlmy jak nazywa się użytkownik:

W powyższym przykładzie użytkownik może wpisać do dwóch pól tekstowych wartości tekstowe. Jest dla nich zdefiniowany model. Za pomocą wyrażeń wartość zostaje automatycznie wyświetlona niżej jako zwykły element strony HTML:

Jak widać na załączonym przykładzie AngularJS odświeża dane ze $scope w czasie rzeczywistym. Jest to niewątpliwie jego największa zaleta. Używając czystego JavaScriptu ilość utworzonego kodu byłaby ogromna. Nawet używając jQuery pomógłby on jedynie szybciej załapać uchwyt dla poszczególnego pola tekstowego – nic więcej.

Grupowanie w obiekty i czysty scope

Pisząc aplikacje w AngularJS musimy dbać o porządek w kontrolerze a przede wszystkim o porządek w $scope. Nigdy nie należy podpinać zmiennych bezpośrednio do scope szczególnie jeżeli tworzą jakiś model biznesowy. Powyższy przykład pokazany dla celów naukowych jest błędny, o wiele lepszym rozwiązaniem będzie zgrupowanie danych osobowych do obiektu osoba. Lepsza organizacja powyższego przykładu:

$scope jest obiektem ważnym, tworzy warstwę widoku-modelu i jest odpowiedzialny za bindowanie danych pomiędzy kontrolerem a widokiem. Jego zaśmiecenie powoduje znaczne straty wydajności w działaniu aplikacji. Odpowiednie grupowanie atrybutów i podpinanie ich jako atrybutów obiektów pomaga w utrzymaniu porządku.

W żadnym wypadku nie możemy uszkodzić albo nadpisać zakresu, możemy jedynie dodawać do niego atrybuty i funkcje, które są nam potrzebne. Istnieją też inne sposoby na dbanie o „lekkość” zakresu i zostaną opisane w kolejnych artykułach.

Użytkownik Andrzej napisał:

17 marca 2018


Poprawka oczywiście nie do pojawienia się w serwisie. Tym bardziej, że została obcięta.
Może tak:
W przykładzie do „Grupowanie w obiekty i czysty scope” niezakończony akapit.
Jest: <p>Nazywasz się {{osoba.imie}} {{osoba.nazwisko}}.<p>

Użytkownik Andrzej napisał:

17 marca 2018


A jeśliby dodać pole wiek. To jak zrobić, aby w wiek od razu się przeliczał w czarodziejski sposób. Na przykład wpisujemy 35, a na stronie widzimy 28 (to dla kobiet :). Może niezbyt przydatne akurat dla wieku, ale ciekaw jestem jak to zrobić. Rozwiązanie tego pokazałoby więcej środka Angulara. Ja w tej chwili nie wiem jak to zrobić. Próbowałem z plusem, ale dodają się stringi…

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0