Architektura Angular 2 - Instytut Informatyki Teoretycznej i Stosowanej
Transkrypt
Architektura Angular 2 - Instytut Informatyki Teoretycznej i Stosowanej
Architektura Angular 2 Architektura Angular 2 Tworzenie serwisów Web 2.0 dr inż. Robert Perliński [email protected] Politechnika Częstochowska Instytut Informatyki Teoretycznej i Stosowanej 6 czerwca 2016 1/41 Plan prezentacji 1 Architektura Angular 2 Moduły Komponenty Szablony Metadane Wiązanie danych Dyrektywy Usługi Wstrzykiwanie zależności 2 Źródła Architektura Angular 2 2/41 Angular 2 https://angular.io/ Warto polecić: http://www.angular2.com/ - zbiór odnośników związanych z Angular 2 https://egghead.io/technologies/angular2 - przewodnik video po Angular 2 Architektura Angular 2 3/41 Architektura Angular 2 Osiem głównych bloków konstrukcyjnych aplikacji Angular 2: 1 Moduły 2 Komponenty 3 Szablony 4 Metadane 5 Wiązanie danych 6 Dyrektywy 7 Usługi 8 Wstrzykiwane zależności To są podstawy dla wszystkich pozostałych elementów aplikacji Angular. Z powodzeniem wystarczą do dalszej pracy i nauki, ale nie jest to wszystko czego będziemy potrzebować. Architektura Angular 2 4/41 Architektura Angular 2 Angular 2: szablon do budowania aplikacji w HTML i JavaScript, składa się z kilku współpracujących bibliotek, niektóre są konieczne, inne opcjonalne. Aplikacja: łączy szablony HTML z wstawkami z Angulara, wykorzystuje komponenty do zarządzania tymi szablonami, dodaje logikę aplikacji w usługach, przekazuje nadrzędny komponent do funkcji ją uruchamiającej. Architektura Angular 2 5/41 Architektura Angular 2 Architektura Angular 2 6/41 1.1. Moduły Najważniejsze: aplikacje Angular składają się z modułów, moduły eksportują różne elementy - klasy, funkcje, wartości importowane przez inne moduły, zalecane jest tworzenie aplikacji jako kolekcji modułów, każdy moduł eksportuje jeden element. Pierwszy stworzony moduł będziej najprawdopodobniej eksportował komponent. Architektura Angular 2 7/41 1.1. Moduły Zwykle aplikację Angular tworzy się z wielu modułów. Typowy moduł jest spójnym blokiem kodu przeznaczonym do jednego celu. Moduły eksportują coś wartościowego z tego kodu, zwykle jeden element jak na przykład klasa. Moduły są opcjonalne ale bardzo wskazane. Angular sam w sobie nie wymaga modułów. TypeScript oraz ES2015 świetnie wspierają moduły. Dlatego właśnie moduły zostały wyróżnione jako jeden z bloków konstrukcyjnych. Używamy tutaj słów: import oraz export. Architektura Angular 2 8/41 1.1. Moduły Pierwszy moduł z jakim się spotkamy będzie prawdopodobnie eksportował komponent. Większość aplikacji ma komponent AppComponent w pliku app.component.ts. Taka jest przyjęta konwencja nazewnictwa. Eksportowanie komponentu: app/app.component.ts export class AppComponent { } Importowanie komponentu: app/main.ts import { AppComponent } from './app.component'; Nazwa modulu to nazwa pliku bez podanego rozszerzenia. Architektura Angular 2 9/41 1.2. Biblioteki modułów Niektóre moduły są bibliotekami innych modułów. Angular sam w sobie jest dostarczony jako biblioteka modułów wewnątrz kilku pakietów npm. Ich nazwy zaczynają się od @angular. Główna biblioteka to @angular/core. Dostarcza ona większość wymaganej funkcjonalności. Inne ważne biblioteki to: @angular/common, @angular/router i @angular/http. Architektura Angular 2 10/41 1.2. Biblioteki modułów Importowanie elementów z bibliotek angular odbywa się tak samo jak z naszych własnych plików: Importowanie funkcji Component: import { Component } from '@angular/core'; Tutaj importowanie odbywa się z modułu biblioteki. Nazwa @angular/core jest ”pusta” - bez śćieżki dostępu. W przypadku importowania naszych własnych modułów podajemy ścieżkę dostępu. Względny adres położenia naszego modułu podajemy zaczynając od ./. Architektura Angular 2 11/41 2. Komponenty Komponent kontroluje pewien stały fragment ekranu, który można nazwać widokiem. Menu nawigacyjne, lista bohaterów, edytor do modyfikacji danych o bohaterach, ... ... to są wszystko widoki kontrolowane przez komponenty. Programista definiuje logikę aplikacji wewnątrz komponentów wewnątrz klas. Logika ta odpowiada za obsługę widoku związanego z danym komponentem. Klasa współdziała z widokiem poprzez zbiór atrybutów i metod (API klasy). Architektura Angular 2 12/41 2. Komponenty Dla przykładu komponent Bohaterowie może mieć atrybut heroes zwracający listę bohaterów uzyskaną z jakiejś usługi. Może mieć metodę selectHero(), która ustawia atrybut selectedHero po kliknięciu na wybranego bohatera. Przykład: app/hero-list.component.ts export class HeroListComponent implements OnInit { constructor(private service: HeroService) { } heroes: Hero[]; selectedHero: Hero; ngOnInit() { this.heroes = this.service.getHeroes(); } selectHero(hero: Hero) { this.selectedHero = hero; } } Angular automatycznie tworzy, aktualizuje i usuwa komponenty zgodnie z działaniami podejmowanymi przez użytkownika aplikacji. Programista może zdefiniować określone akcje w każdym momencie życia komponentu poprzez wstawki programowe (ang. Lifecycle Hooks). Architektura Angular 2 13/41 3.1. Szablony Widok związany z każdym komponentem jest zawsze definiowany razem z jego szablonem. Szablon to jakaś forma kodu HTML określająca jak przedstawić komponent. Szablon wygląda jak regularny kod HTML ale ma wstawki związane z Angular. Przykład: Architektura Angular 2 14/41 3.1. Szablony Szablon wygląda jak regularny kod HTML ale ma wstawki związane z Angular. Przykład: app/hero-list.component.html <h2>Hero List</h2> <p><i>Pick a hero from the list</i></p> <div *ngFor="let hero of heroes" (click)="selectHero(hero)"> {{hero.name}} </div> <hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail> Oprócz klasycznego kodu HTML (znaczniki <h2>, <div>) mamy też *ngFor, {{hero.name}}, (click), [hero], and <hero-detail>. Architektura Angular 2 15/41 3.2. Drzewo komponentów Element <hero-detail> reprezentuje komponent HeroDetailComponent. To jest inny komponent niż HeroListComponent. HeroDetailComponent jest dzieckiem komponentu HeroListComponent. Tag <hero-detail> możemy spokojnie połączyć ze znanymi tagami z języka HTML. W ten sposób łączymy również dyrektywy różnych komponentów w drzewo: Architektura Angular 2 16/41 4.1. Metadane Metadane informują Angular jak przetwarzać klasy. Patrząc na HeroListComponent widać, że jest to tylko klasa. Nie ma w niej nic, co by wskazywało na użycie jakiegoś frameworka, nie ma tam nic z Angulara. Nie jest to komponent dopókie nie poinformujemy o tym Angulara. Informowanie Angulara, że to jest komponent odbywa się właśnie za pośrednictwem metadanych. Najprostszym sposobem dołączenia metadanych w języku TypeScript jest wzorzec dekorator. Architektura Angular 2 17/41 4.1. Metadane Mamy tutaj wykorzystany wzorzec dekorator dla komponentu (@Component), który określa, że klasa bezpośredno pod nim występująca jest komponentem. app/hero-list.component.ts (metadane) @Component({ selector: 'hero-list', templateUrl: 'app/hero-list.component.html', directives: [HeroDetailComponent], providers: [HeroService] }) export class HeroesComponent { ... } Dekorator jest funkcją. Bardzo często ma parametr konfiguracyjny. Dekorator @Component przyjmuje wymagany parametr - obiekt konfigurujący zawierający podrzebne dla Angulara informacje do utworzenia i pokazania związanego z komponentem widoku. Architektura Angular 2 18/41 4.1. Opcje konfiguracyjne komponentu selector - selektor CSS, który oklreśla położenie widoku związanego z komponentem w miejscu występowania podanego tutaj znacznika HTML, np.: <hero-list>. templateUrl - położenie szablonu danego komponentu. directives - tablica komponentów albo dyrektyw wymaganych przez ten szablon. W przypadku naszego szablonu oczekujemy, że Angular doda komponent HeroDetailComponent w miejsce odpowiedniego znacznika. providers - tablica zawierająca listę usług dodawanych do komponentu za pomocą wstrzykiwania zależności. To jest jeden ze sposobów, żeby poinformować Angular, że nasz komponent wymaga konkretnej listy usług. Architektura Angular 2 19/41 4.2. Metadane - widok Funkcja @component przyjmuje obiekt konfiguracyjny i zamienia go w metadane, które są dołączane do definicji klasy komponentu. Angular rozpoznaje i odczytuje te dane i stąd wie jak prawidłowo działać. Szablon, metadane i komponent razem określają widok. W ten sam sposób stosujemy inne matadane wzorca dekorator określające zachowanie Angulara. Niektóre z nich to: @Injectable, @Input, @Output, @RouterConfig. To co musimy wiedzieć o architekturze systemu, to to, że musimy dodać metadane do naszego kodu żeby Angular wiedział co ma robić. Architektura Angular 2 20/41 5.1. Wiązanie danych Bez użycia szablonu aplikacji, programista jest odpowiedzialny za przekazywanie danych do kontrolek HTML i przekształcanie działań użytkownika na odpowiednie akcje z aktualizacją odpowiednich danych. Tworzenie samodzielnie takiej logiki wysyłania/pobierania jest: żmudne, podatne na błędy i straszne w czytaniu (o czym więdzą doświadczenie programiści pracujący z jQuery). Angular wspiera wiązanie danych - mechanizm, który koordynuje zawartość komponentu z przypisanym mu szablonem. Architektura Angular 2 21/41 5.1. Wiązanie danych Dodajemy znacznki wiązania danych do szablonu HTML, które określają jak połączyć obie strony. Istnieją cztery formy składni wiązania danych: do drzewa DOM, od drzewa DOM albo w obu kierunkach. Architektura Angular 2 22/41 5.1. Jednokierunkowe wiązanie danych Poniższy kod przedstawia trzy formy wiązania danych: app/hero-list.component.html (fragment) <div>{{hero.name}}</div> <hero-detail [hero]="selectedHero"></hero-detail> <div (click)="selectHero(hero)"></div> wstawianie (ang. interpolation) wyświetla właściwość hero.name komponentu wewnątrz <div>, wiązanie właściwości [hero] (ang. property binding ) przekazuje wybranego bohatera (selectedHero) z nadrzędnego komponentu HeroListComponent do właściwości hero elementu/znacznika dziecka HeroDetailComponent, wiązanie zdarzenia (click) (ang. event binding ) wywołuje metodę selectHero komponentu kiedy użytkownik kliknie wybranego bohatera. Architektura Angular 2 23/41 5.2. Dwukierunkowe wiązanie danych Czwartą formą jest dwukierunkowe wiązanie danych (ang. two-way data binding ), która łączy wiązanie właściwości i wiązanie zdarzenia w jednej notacji używając dyrektywy ngModel. Przykład takiej dyrektywy z komponentu wyświetlającego szczegóły naszego bohatera: <input [(ngModel)]="hero.name"> W dwukierunkowym wiązaniu danych dane przepływają z właściwości komponentu do kontrolki HTML jak przy wiązaniu właściwości. Zmiany dokonywane przez użytkownika przepływają w przeciwnym kierunku do komponentu, zmieniając wartość odpowiedniej właściwości komponentu na właśnie wprowadzoną. Architektura Angular 2 24/41 5.3. Wiązanie danych Angular przetwarza wszystkie wiązania danych jednorazowo w jednym cyklu zdarzeń JavaScript, przetwarzając drzewo komponentów aplikacji algorytmem przeszukiwania w głąb. Wiązanie danych odgrywa ważna rolę w komunikacji między szablonem i jego komponentem... Architektura Angular 2 ... jak również między rodzicem i komponentami dzieci. 25/41 6. Dyrektywy Szablony Angular są dynamiczne. Podczas generowania z nich widoku, Angular przekształca DOM zgodnie z instrukcjami podanymi przez dyrektywy. Dyrektywa jest klasą z metadanymi dyrektywy. W TypeScript stosujemy dekorator @Directive, który łączy metadane z klasą. Architektura Angular 2 26/41 6. Dyrektywy Jedną z form dyrektywy jest komponent. Komponent to dyrektywa z dołączonym szablonem. Dekorator @Component jest w rzeczywistości dekoratorem @Directive rozszerzonym do obsługi szablonów. W opisie architektury komponent wyróżniono spośród innych dyrektyw, ze względu na jego ważność i centralne miejsce w aplikacjach Angular. Są dwa rodzaje dyrektyw, które nazywa się strukturalnymi/konstrukcyjnymi i atrybutowymi. Zwykle pojawiają się wewnątrz elementu jak atrybuty, czasem jako nazwy, ale częściej jako cel przypisania albo wiązania. Można oczywiście pisać własne dyrektywy. Architektura Angular 2 27/41 6. Dyrektywy konstrukcyjne Dyrektywy konstrukcyjne: zmieniają ułożenie dodająć, usuwając albo zastępując elementy w drzewie DOM, przykłady dwóch dyrektyw konstrukcyjnych: <div *ngFor="let hero of heroes"></div> <hero-detail *ngIf="selectedHero"></hero-detail> *ngFor nakazuje wykonać tyle egzemplarzy znacznika <div> ile jest w tablicy heroes, *ngIf uwzględni komponent HeroDetail tylko jeśli wybrany bohater istnieje. Architektura Angular 2 28/41 6. Dyrektywy atrybutowe Dyrektywy atrybutowe: zmieniają zachowanie albo wygląd istniejącego elementu, w szablonie wyglądają jak normalne atrybuty HTML, przykładem może być dyrektywa ngModel, która odpowiada za dwukierunkowe wiązanie danych: <input [(ngModel)]="hero.name"> zmienia ona zachowanie elementu (zwykle <input>) ustawiając wartość wyświetlanej właściwość oraz reagując na zdarzenie wykonywania zmian. Angular posiada kilka innych dyrektyw, które: albo zmieniają strukturę elementów w widoku, np. ngSwitch albo zmieniają wygląd elementów DOM i komponentów, np. ngStyle czy ngClass. Architektura Angular 2 29/41 7. Usługi Usługa jest ogólną kategorią obejmującą jakąkolwiek wartość, funkcję czy cechę, która jest potrzebna w naszej aplikacji. Niemal wszystko może być usługą. Zwykle jest klasą z wąskim, precyzyjnie określonym celem. Powinna spełniać jakąś specyficzną funkcję i powinna robić to dobrze. Przykładowe usługi: obsługa logowania, dostęp do danych, wymiana komunikatów, kalkulator podatkowy, konfiguracja aplikacji. Architektura Angular 2 30/41 7. Usługi Angular nie zawiera żadnej definicji usługi, nie ma klasy bazowej ServiceBase... Jednka usługi są zasadnicze dla działania każdej aplikacji Angular. Przykład usługi wyświetlającej logi w przeglądarce: app/logger.service.ts (tylko klasa) export class Logger log(msg: any) { error(msg: any) { warn(msg: any) { } Architektura Angular 2 { console.log(msg); } console.error(msg); } console.warn(msg); } 31/41 7. Usługi Usługa HeroService pobiera listę bohaterów i zwraca ją w postaci obietnicy. app/hero.service.ts (tylko klasa) export class HeroService { constructor( private backend: BackendService, private logger: Logger) { } private heroes: Hero[] = []; getHeroes() { this.backend.getAll(Hero).then( (heroes: Hero[]) => { this.logger.log(‘Fetched ${heroes.length} heroes.‘); this.heroes.push(...heroes); // fill cache }); return this.heroes; } } Bazuje na dwoch innych usługach: LoggerService oraz BackendService, która odpowiada za komunikację z serwerem. Usługi są wszędzie. Architektura Angular 2 32/41 7. Usługi Nasze koponenty w dużym stopniu korzystają z usług. Polegają na usługach w celu spełnienia większości obowiązków. Komponenty: nie pobierają danych z serwera, nie walidują danych wejściowych, nie wyświetlają logów bezpośrednio do konsoli. Wszystkie takie zadania są delegowane do usług. Zadaniem komponentu jest tylko funkcjonalności użytkownikowi i nic więcej. Pośredniczy on pomiędzy widokiem a logiką aplikacji (która często reprezentuje pewną wiedzę o modelu). Dobry komponent udostępnia właściwości i metody do wiązania danych. Wszystkie nietrywialne zadania są delegowane do usług. Architektura Angular 2 33/41 7. Usługi Angular nie wymusza takich zasad. Nie zgłosi błędu kiedy stworzymy komponent ”zlew kuchenny” zawierający 3000 lini kodu. Angular pomaga nam korzystać z tych zasad ułatwiając dokonywanie podziału logiki aplikacji na usługi i uczynienie tych usług dostępnymi dla komponentów dzięki wstrzykiwaniu zależności. Architektura Angular 2 34/41 8.1. Wstrzykiwanie zależności Wstrzykiwanie zależności (ang. dependency injection) to mechanizm dostarczania w pełni funkcjonalnych klas razem ze wszystkimi ich zależnościami. Większość zależności to usługi. Angular używa wstrzykiwania zależności aby dostarczyć komponentom usług, których potrzebują. Architektura Angular 2 35/41 8.1. Wstrzykiwanie zależności Dzięki TypeScript Angular wie jakich usług potrzebuje komponent patrząc na typ parametrów konstruktora: app/hero-list.component (konstruktor) constructor(private service: HeroService) { } Komponent HeroListComponent potrzebuje usługi HeroService. Przy tworzeniu komponentu Angular pyta Injector o usługi, których potrzebuje. Injector zarządza zasobnikiem instancji różnych usług, które wcześniej utworzył. Jeśli potrzebnej usługi nie ma w zasobniku, to jest ona tworzona, dodawana do zasobnika i dopiero przekazywana do Angulara. Po uzyskaniu wszystkich usług i przekazaniu ich do Angulara, może on uruchomić konstruktor komponentu. To właśnie nazywa się wstrzykiwaniem zależności. Architektura Angular 2 36/41 8.2. Wstrzykiwanie zależności Wstrzykiwanie zależności usługi HeroService wygląda mniej więcej tak: Jeśli Injector nie posiada usługi HeroService to skąd wie jak ją utworzyć? Wcześniej Injector musi mieć zarejestrowanego dostawcę (ang. provider) usługi HeroService. Dostawca to coś co potrafi utworzyć usługę i ją zwrócić. Zwykle jest to klasa usługi sama w sobie. Architektura Angular 2 37/41 8.2. Wstrzykiwanie zależności - rejestracja dostawcy Dostawcę można zarejestrować na każdym poziomie drzewa komponentów naszej aplikacji. Robimy to często na najwyższym poziomie przy uruchamianiu, te same instancje usług są dostępne w całej aplikacji: app/main.ts (fragment) bootstrap(AppComponent, [BackendService, HeroService, Logger]); Można też zarejestrować dostawcę na poziomie wybranego komponentu: app/main.ts (fragment) @Component({ providers: [HeroService] }) export class HeroesComponent { ... } w tym przypadku dostajemy nową instancję usługi dla każdej instancji komponentu. Architektura Angular 2 38/41 8.2. Wstrzykiwanie zależności - podsumowanie wstrzykiwanie zależności jest połączone z Angular i wszędzie używane, Injector jest głównym mechanizmem: zarządza zasobnikiem instancji usług, które sam utworzył, tworzy nowe instancje usług używając dostawcy (provider ), dostawca jest ”przepisem” na utworzenie usługi, musimy rejestrować dostawców w ramach Injectora. Architektura Angular 2 39/41 Pozostałe elementy w Angular 2 Animacje - jest do tego specjalna biblioteka, Bootstrap - sposoby konfigurowania i uruchamiania aplikacji, Wykrywanie zmian - sposoby określania stref (ang. zones) ekranu, które będą aktualizowane przy zmianie danych, Mechanizm trasowania - komponent Router odpowiedzialny za obsługę wielu ekranów podobnie jak przeglądarki obsługują wiele adresów URL, Zdarzenia - drzewo DOM zgłasza zdarzenia, tak samo komponenty i usługi; Angular ma mechanizmy obsługi zdarzeń, Formularze - wsparcie dla scenariuszy złożonych danych wejściowych, walidacja w HTML, HTTP - wbudowany klient HTTP do pobierania danych, zapisu danych i wywoływania akcji po stronie serwera, Wstawki programowe - obsługa dodaktowej funkcjonalności w ramach cyklu życia komponentu, Strumienie - przetwarzania wyświetlanych danych (filtry w Angular1), Testowanie - dostęp do biblioteki do testów jednostkowych. Architektura Angular 2 40/41 Źródła https://angular.io/ https://pl.wikipedia.org/wiki/TypeScript https://www.typescriptlang.org/ http://codeguru.geekclub.pl/baza-wiedzy/ wprowadzenie-do-programowania-w-typescript-wstep,3575 https://developer.mozilla.org/en-US/docs/Web/JavaScript/ Reference/Functions/Arrow_functions Architektura Angular 2 41/41