AngularJS

Pracując w AngularJS organizujemy projekt inaczej niż w klasycznym JavsScript. Jednym z popularniejszych sposobów organizacji projektu jest MVC.

  • Model - odpowiada za dane w aplikacji. Mogą one być pobierane z plików JSON, zewnętrznych usług lub z bazy danych.
  • View - aby zaprezentować dane z modelu potrzebny jest nam widok. Widok w AngularJS to nic innego jak dokuemnt HTML wraz ze składnią systemu szablonów {{}}
  • Controller - to kod JavaScipt który łączy model i widok w całość oraz pozwala na przeprowadzanie interakcji z użytkownikiem.

Model

Model to dane pokazywane użytkownikom w widokach, z którymi użytkownicy mogą wchodzić w interakcje.

album = { id: "3B0PgLmgaW0gJth55ApWbw" image: "https://i.scdn.co/image/fa8a3b68578c65fff17f59cc5e5058b4e2fc48b2" name: "Transistor Original Soundtrack" } var album = { id: "3B0PgLmgaW0gJth55ApWbw", image: "https://i.scdn.co/image/fa8a3b68578c65fff17f59cc5e5058b4e2fc48b2", name: "Transistor Original Soundtrack" };

Modelem może być dowolny obiekt JavaScript

Widok (ang. View)

Widok to warstwa reprezentacyjna czyli to co de facto użytkownik widzi na ekranie przeglądarki. W AngularJS to nic innego jak kod HTML okraszony wyrażeniami {{}}. Warto wspomnieć, że wyrażenia w {{}} są kompilowane przez AngularJS i zachowują się prawie jak zwykły JavaScript (obsługują wyrażenia arytmetyczne, logiczne, konkatenacje etc).

Controller

Implementacja kontrolera w AngularJS polega na dodaniu funkcji (konstruktora), której argumentami są nazwy wykorzystywanych usług ($scope, $http, $routeParams, etc.). Dla naszych potrzeb niezbędna jest usługa $scope. $scope jest obiektem łączącym Widok i Kontroler, stanowi on kontekst dla widoku ($scope.model można wyświetlić przez {{ model }}).

$rootScope

Hierarchia $scope'ów w aplikacji jest drzewem, którego korzeniem jest zawsze dostępny $rootScope. Aby go użyć w kontrolerze, wystarczy dodać go do listy wymaganych usług.

Przedyskutuj z mentorem czym różnią się rozwiązania w zagnieżdżeniach $scope'ów: $parent, controlerAs, prototype inheritance.

Dodatkowo, aby powiązać widok z naszym kontrolerem musimy posłużyć się dyrektywą ng-controller. Określa ona, który kontroler ma odpowiadać za dany element (i jego zawartość).

angular.module('app') .controller 'AlbumController', ($scope) -> $scope.album = id: "3B0PgLmgaW0gJth55ApWbw" image: "https://i.scdn.co/image/fa8a3b68578c65fff17f59cc5e5058b4e2fc48b2" name: "Transistor Original Soundtrack" angular.module('app') .controller('AlbumController', function($scope) { $scope.album = { id: "3B0PgLmgaW0gJth55ApWbw", image: "https://i.scdn.co/image/fa8a3b68578c65fff17f59cc5e5058b4e2fc48b2", name: "Transistor Original Soundtrack" }; });

Nazewnictwo

Zazwyczaj do nazwy kontrolera (funkcji) dodaje się suffixController lub Ctrl

Aplikacja

Wreszcie, żeby angular skompilował nasze widoki i podpiął kontrolery trzeba stworzyć moduł aplikacji app i wskazać element, który jest korzeniem naszej aplikacji.

angular.module 'app', [] angular.module('app', []);

Moduły

angular.module() jest funkcją typu getter/setter:

angular.module(moduleName, dependencies) rejestruje moduł moduleName, który wymaga modułów wymienionych w liście dependencies

angular.module(moduleName) zwraca wcześniej zarejestrowany moduł moduleName

Upewnij się, że pobierasz moduł po jego zarejestrowaniu!

Zadanie dla Ciebie:

  • Wypróbuj AlbumController modyfikując index.html tak, aby wyświetlić kafelek albumu
  • Zaimplementuj TrackController który będzie odpowiedzialny za wyświetlenie pojedynczego wiersza tabeli utworów
  • Powiąż kontroler z widokiem i wyświetl model w tabeli
  • Popraw błędy typu GET http://localhost:8888/%7B%7B%20album.image%20%7D%7D 404 (Not Found)
  • Pytania?

Struktura

Spróbuj umieścić AlbumController oraz TrackController odpowiednio w plikach src/routes/album/album.js i src/routes/album/track.js. Ułatwi Ci to potem kolejne zmiany w aplikacji.

ng-style

ng-style to dyrektywa, która pozwala powiązać model ze stylami danego elementu.

.controller 'Controller', ($scope) -> $scope.textColor = 'red' .controller('Controller', function($scope) { $scope.textColor = 'red'; }) I'm {{ textColor }}!

ng-model two-way binding

Aby obsłużyć dane pochodzące od użytkownika, możemy wykorzystać two-way bindings przez dyrektywę ng-model.

Hello !

angular.module('app') .controller 'GreetingController', ($scope) -> $scope.name = 'Stefan' # wartość początkowa angular.module('app') .controller('GreetingController', function($scope) { $scope.name = 'Stefan' // wartość początkowa });

ng-click

ng-click to dyrektywa która pozwala nam powiązać kliknięcie przez użytkownika z wywołaniem funkcji lub wyrażenia.

.controller 'Controller', ($scope) -> $scope.x = 0 $scope.y = 'a' $scope.clickMe = -> alert 'Hi!' .controller('Controller', function($scope) { $scope.x = 0; $scope.y = 'a'; $scope.clickMe = function() { alert('Hi!'); }; })

ng-class

ng-class to dyrektywa która pozwala nam powiązać klasy elementu z modelem. Przyjmuje mapę nazw klas i wyrażeń, które muszą być spełnione, żeby dana klasa była dodana do elementu.

Zadanie dla Ciebie:

  • Zaimplementuj NavbarController, odpowiedzialny za pasek nawigacyjny i pole wyszukiwania
  • Przetestuj działanie two-way data binding na polu wyszukiwarki wyświetlając obok logo strony wyszukiwaną frazę
  • Dodaj czyszczenie pola wyszukiwania za pomocą przycisku
  • Usuń klasę minimized z elementu <nav> kiedy pole wyszukiwania jest puste
  • Pytania?

Struktura

Kontroller NavbarController postaraj się umieścić w apliku src/navbar/navbar.js

Przykładowe dane

Do tej pory nasza aplikacja za wiele nie robiła, a nasz model był zwykłym pojedynczym obiektem. Wypadałoby zacząć implementację bardziej realistycznej aplikacji z większą ilością danych.

Przygotowaliśmy dla Ciebie plik search.json, który zawiera pobrane ze Spotify wyniki wyszukiwania słowa “transistor”, które posłużą nam jako wypełniacz do, jeszcze aktualnie, sztywnego szablonu :)

Aby dołączyć dane z pliku search.json do naszej aplikacji narazie po prostu wkleimy jego zawartość do naszego kontrolera (MainController):

Tak jest to mało pro rozwiązanie ale zaimplementowanie tego lepiej wymagałoby znajomości usług, które poznamy później.

Zadanie dla Ciebie:

  • Stwórz MainController i dodaj go do body
  • Pobierz plik search.json
  • Wklej jego zawartość do MainController tak aby był dostępny w $scope, np. pod zmienną searchResults

Struktura

Na tą chwilę kontroller MainController możesz umieścić w pliku src/app/app.js.

ng-repeat

Aby wyświetlić listę elementów ze zmiennej, np. searchResults, będziemy musieli posłużyć się dyrektywą ng-repeat. ng-repeat powieli nam element DOM, do którego została przypisana tyle razy ile jest elementów w tablicy.

Zapis ng-repeat="artist in searchResults.artists.items" oznacza tyle co utwórz zmienną o nazwie artist, która pobiera dane ze zmiennej searchResults.artists.items. Dyrektywa ng-repeat dosłownie przejdzie po każdym elemencie tablicy searchResults.artists.items i na chwilę wpisze go do zmiennej artist przy okazji kopiując element DOM do którego została przypisana. Zmienna artist zostanie udostępniona i będzie można jej użyć do wypełnienia szablonu danymi.

Zadanie dla Ciebie:

  • Zaimplementuj ng-repeat z użyciem danych z search.json
  • Wypełnij szablon danymi o znalezionych artystach, albumach i utworach ({{}})
  • O ile występują jakieś błędy w konsoli spróbuj je naprawić
  • Pytania?

Efekt

MVC Efekt