Wprowadzenie do Angular 2 - Instytut Informatyki Teoretycznej i

Transkrypt

Wprowadzenie do Angular 2 - Instytut Informatyki Teoretycznej i
Wprowadzenie do Angular 2
Wprowadzenie do Angular 2
Tworzenie serwisów Web 2.0
dr inż. Robert Perliński
[email protected]
Politechnika Częstochowska
Instytut Informatyki Teoretycznej i Stosowanej
30 maja 2016
1/61
Plan prezentacji
1
Trochę informacji o Angular 2
2
Hello World w Angular 2
Przygotowanie projektu
Pierwszy komponent
3
Rozbudowa aplikacji
4
Źródła
Wprowadzenie do Angular 2
2/61
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
Wprowadzenie do Angular 2
3/61
egghead.io - nauka technologii internetowych
Wprowadzenie do Angular 2
https://egghead.io
4/61
Cechy i zalety - jeden kod na wszystkie platformy
Nowoczesne aplikacje sieciowe:
wykorzystanie nowoczesnych możliwości platformy sieciowej pozwala
na dostarczanie stron wyglądających i działających jak aplikacje
desktopowe,
wysoka wydajność,
działaie bez dostępu do internetu,
brak potrzeby instalacji.
Aplikacje natywne:
Można tworzyć natywne aplikacje korzystając z takich technologii jak:
Ionic Framework - http://ionicframework.com/
Native Script,
React Native.
Aplikacje na komputery stacjonarne:
pozwala tworzyć aplikacje z wersją instalacyjną na Mac, Windows i
Linux’a,
używamy tych samych metod co w technologiach sieciowych,
korzystamy z natywnego API danej platformy.
Wprowadzenie do Angular 2
5/61
Cechy i zalety - szybkoś i wydajność
Generowanie kodu:
Angular przekształca szablony w kod wysoko zoptymalizowany dla
dzisiejszych maszyn wirtualnych JavaScript,
dostarcza wszystkich zalet kodu pisanego ręcznie z wykorzystaniem
produktywności szablonu aplikacji.
Universalność:
dostarcza wygląd aplikacji zbudowanej w oparciu o node.js, .NET,
PHP czy inne serwery,
renderuje widok do HTML i CSS niemal natychmiastowo,
przygotowuje dobry grunt dla aplikacji pod optymalizację SEO (search
engine optimization).
Podział kodu:
szybkie wczytywanie aplikacji dzięki komponentowi Router
(automatyczne dzielenie kodu),
użytkownicy wczytują tylko ten kod, który jest potrzebny do
wygenerowania żądanego widoku.
Wprowadzenie do Angular 2
6/61
Cechy i zalety - produktywność
Szablony:
szybkie tworzenie widoków (interfejsów użytkownika) dzięki prostej ale
potężnej składni szablonów.
Angular CLI:
interfejs lini komand dla Angular, coś na wzór npm dla node.js,
szybkie tworzenie szablonu aplikacji,
dodawanie komponentów i testów,
natychmiastowe instalowanie/wdrażanie,
http://ngcli.github.io/
Zintegrowane środowisko programistyczne:
inteligentne dopełnianie kodu,
wykrywanie błędów i inne informacje zwrotne w popularnych
edytorach.
Wprowadzenie do Angular 2
7/61
Cechy i zalety - pełne wsparcie przy tworzeniu
Testowanie:
środowisko Karma (https://karma-runner.github.io/) dla
testów jednostkowych,
informacja o błędach przy każdym zapisywaniu projektu.
Protractor (http://angular.github.io/protractor) zapewnia
szybkość i stabilność scenariuszom testowym.
Animacje:
tworzenie skomplikowanych choreografi i przebiegów czasowych
animacji wysokiej wydajności,
wystarczy mała ilość kodu dzięki intuicyjnemu API Angular.
Dostępność:
tworzenie dostępnych aplikacji z komponentami dla ARIA (aplikacje
internetowe wysokiej dostępności, np. dla osób niepełnosprawnych),
tworzenie przewodników dla programistów (żeby aplikacje były wysoko
dostępne),
wbudowana infrakstuktura do testowania dla projektu a11y.
Wprowadzenie do Angular 2
8/61
Przytotowanie projektu
Przygotowanie projektu czyli prawie Hello World:
1
2
instalacja Node.js i npm - bez tego nie popracujemy
utworzenie i konfiguracja projektu:
tworzymy katalog projektu:
mkdir empty-project
cd empty-project
dodajemy definicje pakietu i pliki konfiguracyjne:
package.json
tsconfig.json
typings.json
systemjs.config.js
instalacja pakietów
npm install
Wprowadzenie do Angular 2
9/61
package.json - rekomendowany zbiór pakietów
package.json
{
"name": "empty-project",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@angular/common": "2.0.0-rc.1",
"@angular/compiler": "2.0.0-rc.1",
"@angular/core": "2.0.0-rc.1",
"@angular/http": "2.0.0-rc.1",
"@angular/platform-browser": "2.0.0-rc.1",
"@angular/platform-browser-dynamic": "2.0.0-rc.1",
"@angular/router": "2.0.0-rc.1",
"@angular/router-deprecated": "2.0.0-rc.1",
"@angular/upgrade": "2.0.0-rc.1",
"systemjs": "0.19.27",
"es6-shim": "^0.35.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12",
"angular2-in-memory-web-api": "0.0.7",
"bootstrap": "^3.3.6"
},
"devDependencies": {
"concurrently": "^2.0.0",
"lite-server": "^2.2.0",
"typescript": "^1.8.10",
"typings":"^0.8.1"
}
}
Wprowadzenie do Angular 2
10/61
package.json
Aplikacje Angular i sam Angular zależy od funkcjonalności dostarczanej
przez innych dostawców. Zarządzamy tym z użyciem menadżera NPM.
Zbiór pakietów przedstawiony w package.json:
dobrze współpracuje ze sobą,
zawiera wszystko co potrzebne do zbudowania przykładowej aplikacji
i jest to więcej niż potrzeba w wielu aplikacjach,
pobranie większej liczby pakietów nie wpływa negatywnie na działanie
aplikacji,
na serwer wysyła się tylko to, czego aplikacja naprawdę potrzebuje.
Zależności:
dependencies - pakiety wymagane do działania aplikacji,
devDependencies - pakiety wymagane tylko przy tworzeniu aplikacji
instalacja pakietów produkcyjnych:
npm install hello-app --production
Wprowadzenie do Angular 2
11/61
package.json
Trzy kategorie wymaganych pakietów:
użytkowe (ang. feature) - dostarczają naszej aplikacji podstawowe i
użytkowne możliwości,
wygładzające (ang. polyfill) - dostarczają funkcjonalności, która
nie jest obecna we wszystkich przeglądarkach,
inne - pozostałe pakiety wspierające naszą aplikację, np. bootstrap.
Wprowadzenie do Angular 2
12/61
package.json
Pakiety użytkowe:
@angular/core - najważniejsze pakiety dla działania aplikacji, obsługa wszystkich
metadanych dotyczących: dekoratorów, komponentów, dyrektyw, wstrzykiwania
zależności oraz cyklu życia komponentów i związanych z tym zdarzeń i wywołań,
@angular/common - często używane usługi, strumienie, dyrektywy dostarczone
razem z Angular,
@angular/compiler - kompilator szablonów dostarczany razem z Angular,
@angular/platform-browser - obsługa funkcjonalności związanej z DOM i
przeglądarką,
@angular/platform-browser-dynamic - dostarcza i uruchamia metody
pozwalające aplikacji kompilować szablony po stronie klienta, używany do
uruchamiania aplikacji podczas jej tworzenia,
@angular/http - klient http w Angular,
@angular/router - komponent do obsługi routingu,
@angular/upgrade - zbiór narzędzi pozwalający zaktualizować aplikację napisaną
w Angular 1,
system.js - obsługa dynamicznego wczytywania modułów, kompatybilna z
ES2015.
Wprowadzenie do Angular 2
13/61
package.json
Pakiety wygładzające:
es6-shim - pakiet zapewnia wsparcie dla najważniejszych cech
ES2015(ES6); z czasem przestanie być potrzebny,
reflect-metadata - obsługa zeleżności między Angular i
kompilatorem TypeScript; aktualizacja wersji zależności TypeScript
musi odbywać się niezależnie od wersji Angular,
rxjs - Reactive Extensions Library for JavaScript; odpowiada za
wybór właściwej wersji typów obserwowanych (ang. Observable type)
bez konieczności oczekiwania na wydanie nowej wersji Angular,
zone.js - obsługa właściwego kontekstu wywoływania funkcji
asynchronicznych; tutaj również chodzi o uniezależnienie tej
funkcjonalności od wersji Angular.
Wprowadzenie do Angular 2
14/61
package.json
Pozostałe pakiety:
angular2-in-memory-web-api - biblioteka służąca do symulowania
internetowego api, dobra we wczesnej fazie projektu,
bootstrap - HTML i CSS framework, ładny wygląd, tworzenie RWD.
Wprowadzenie do Angular 2
15/61
package.json - devDependencies
Pakiety wykorzystywane przy tworzeniu:
concurrently - narzędzie pozwalające uruchamiać wiele poleceń
npm jednocześnie,
lite-server - lekki serwer internetowy ze świetnym wsparciem dla
Angular, wykorzystywany przy tworzeniu aplikacji,
typescript - obsługa języka TypeScript i kompilator tsc,
typings - menadżer dla plików definicji do TypeScript.
Wprowadzenie do Angular 2
16/61
package.json - skrypty
package.json - scripts
{
"name": "empty-project",
"version": "1.0.0",
"scripts": {
"start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
"lite": "lite-server",
"postinstall": "typings install",
"tsc": "tsc",
"tsc:w": "tsc -w",
"typings": "typings"
},
"license": "ISC",
"dependencies": {
...
},
"devDependencies": {
...
}
}
Wprowadzenie do Angular 2
17/61
package.json - skrypty
Skrypty (uruchamiane poleceniem npm run):
npm start - uruchamia kompilator i serwer w tym samym czasie, oba
w trybie śledzenia zmian,
npm run tsc - jednorazowe uruchomienie kompilatora tsc,
npm run tsc:w - kompilator w trybie śledzenia zmian,
npm run lite - ruchamia lite-server,
npm run typings - uruchamia osobno narzędzie do obsługi definicji
dla TypeScript,
npm run postinstall - wywoływane automatycznie po udanej
instalacji pakietów npm; instaluje definicje pakietów dla TypeScript.
Ręczne uruchomienie concurrently:
./node_modules/concurrently/src/main.js "npm run tsc:w" "npm run lite"
Wprowadzenie do Angular 2
18/61
tsconfig.json - ustawienia kompilatora tsc
tsconfig.json - ustawienia kompilatora tsc
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules",
"typings/main",
"typings/main.d.ts"
]
}
Wprowadzenie do Angular 2
19/61
typings.json - pliki definicji dla TypeScript
typings.json
{
"ambientDependencies": {
"es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
"jasmine": "registry:dt/jasmine#2.2.0+20160412134438",
"node": "registry:dt/node#4.0.0+20160509154515"
}
}
Wprowadzenie do Angular 2
20/61
systemjs.config.js - wersja minimalna
(function(global) {
// zmienna map informuje system wczytywania pakietów gdzie szukać podanego pakietu
var map = {
'myApp':
'folderApp', // 'dist',
'rxjs':
'node_modules/rxjs',
'@angular':
'node_modules/@angular'
};
// zmienna packages informuje system jak wczytać pakiet jeśli nie podano pliku i/lub rozszerzenia
var packages = {
'myApp':
{ main: 'main.js', defaultExtension: 'js' },
'rxjs':
{ defaultExtension: 'js' }
};
var packageNames = [
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/platform-browser',
'@angular/platform-browser-dynamic'
];
// dodaje wpisy o pakietach w poniższej formie:
//
'@angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
var config = {
map: map,
packages: packages
}
System.config(config);
})(this);
Wprowadzenie do Angular 2
21/61
systemjs.config.js
(function(global) {
var map = {
'myApp':
'folderApp', // 'dist',
'rxjs':
'node_modules/rxjs',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'@angular':
'node_modules/@angular'
};
var packages = {
'myApp':
{ main: 'main.js', defaultExtension: 'js' },
'rxjs':
{ defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' },
};
var packageNames = [
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/http',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/router',
'@angular/router-deprecated',
'@angular/testing',
'@angular/upgrade',
];
packageNames.forEach(function(pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
var config = {
map: map,
packages: packages
}
System.config(config);
})(this);
Wprowadzenie do Angular 2
22/61
SystemJS - jak to działa?
SystemJS:
narzędzie do wczytywania aplikacji i poszczególnych modułów, jedno z wielu,
alternatywą może być np. webpack (https://webpack.github.io/),
jak wszystkie inne narzędzia, wymaga on konfiguracji,
wszystkie konfiguracje narzędzi wczytujących stają się wraz z rozwojem
aplikacji skomplikowane,
dobrze więc dobrze znać narzędzie, którego się używa,
tworzymy więc plik systemjs.config.js.
Wprowadzenie do Angular 2
23/61
SystemJS - jak to działa?
Konfiguracja SystemJS:
najpierw mapy wskazujące miejsce, gdzie SystemJS ma szukać aby
zaimportować określony moduł:
systemjs.config.js
// zmienna map informuje system
var map = {
'myApp':
'rxjs':
'angular2-in-memory-web-api':
'@angular':
};
gdzie szukać podanego pakietu
'folderApp', // 'dist',
'node_modules/rxjs',
'node_modules/angular2-in-memory-web-api',
'node_modules/@angular'
następnie rejestrujemy wszystkie nasze pakiety:
wszystkie pakiety z których korzystamy,
nasz własny (na razie jedyny) pakiet myApp,
opis pakietu myApp informuje system co robić, kiedy pojawi się żądanie
modułu z katalogu folderApp:
import { AppComponent } from ’./app.component’;
Wprowadzenie do Angular 2
24/61
Tworzenie kodu - pierwszy komponent
Tworzymy katalog dla pierwszego komponentu: mkdir folderApp
folderApp/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>Witaj w moim projekcie ...</h1>'
})
export class FirstComponent { }
FirstComponent będzie korzeniem całej aplikacji.
Każda aplikacja ma przynajmniej jeden taki komponent.
Zwykle nazywa się go AppComponent.
Komponenty są podstawowymi blokami konstrukcyjnymi aplikacji Angular.
Kontrolują jakiś obszar ekranu - widok - poprzez związany z nimi szablon.
Wprowadzenie do Angular 2
25/61
Struktura komponentu
Struktura komponentu:
folderApp/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>Witaj w moim projekcie ...</h1>'
})
export class FirstComponent { }
jedno lub więcej poleceń import do tego co potrzebujemy,
dekorator @Component - mówi aplikacji Angular, jakiego szablonu użyć i jak
utworzyć komponent,
klasa komponentu, kontroluje wygląd i zachowanie widoku poprzez jego
szablon.
Wprowadzenie do Angular 2
26/61
Importowanie
Aplikacje Angular mają modułową budowę.
Składają się z wielu plików, z których każdy ma określone przeznaczenie.
Angular sam w sobie jest zbudowany z modułów. Jest kolekcją modułów,
każdy składający się z kilku powiązanych funkcji.
Kiedy potrzebujemy czegoś z bibliotek - importujemy to:
import { Component } from ’@angular/core’;
import z podstawowej biblioteki Angular, dostęp do wzorca dekorator.
Wprowadzenie do Angular 2
27/61
Dekorator @Component
folderApp/app.component.ts
@Component({
selector: 'my-app',
template: '<h1>Witaj w moim projekcie ...</h1>'
})
Component to funkcja dekoratora, pobiera jeden argument - objekt JS
zawierający metadane.
Wywołujemy tę funkcje na obiekcie klasy poprzedzając ja symbolem @.
@Component to dekorator, który pozwala nam związać jakieś metadane z
klasą komponentu.
Metadane mówią aplikacji Angular jak utworzyć i używać komponentu.
selector określa prosty selektor CSS dla elementu HTML - wszędzie gdzie
wystąpi znacznik my-app będzie instancja FirstComponent.
template - szabon dla widoku - renderowany w czasie tworzenia widoku;
Może zawierać zmienne, właściwości komponentu, może się odwoływać do
innych komponentów tworząc drzewo komponentów.
Wprowadzenie do Angular 2
28/61
Klasa komponentu
folderApp/app.component.ts
export class AppComponent { }
Tutaj klasa komponentu jest pusta, nic nie robi.
Później można ją rozwinąć o właściwości i jakąś logikę.
Eksportujemy klasę na zewnątrz (export) - można ja zaimportowć
gdziekowiek w aplikacji (import).
Wprowadzenie do Angular 2
29/61
Plik wejściowy aplikacji
folderApp/main.ts
import { bootstrap }
from '@angular/platform-browser-dynamic';
import { FirstComponent } from './app.component';
bootstrap(FirstComponent);
Trzeba gdzieś wczytać utworzony komponent.
Importujemy dwie rzeczy:
funkcję bootstrap przeglądarki dla Angular’a,
główny komponent aplikacji FirstComponent z odpowiedniego
pliku/modułu,
odpalamy aplikację (bootstrap) z odpowiednim komponentem.
Funkcja uruchamiająca aplikację zależy od platformy, nie jest więc w
@angular/core.
Aplikację można załadować na przykład na tablecie z NativeScript.
Podzła na komponent i plik go ładujący jest wzorcowy, zapewnia porządek.
Wprowadzenie do Angular 2
30/61
Plik index.html
<html>
<head>
<title>Pierwsza plikacja w Angular 2 </title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('myApp').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Wczytywanie...</my-app>
</body>
</html>
Wprowadzenie do Angular 2
31/61
Zbudowanie i uruchomienie aplikacji
Kompilujemy i uruchamiamy aplikację:
npm start
Można dodać jeszcze plik CSS aby nasz napis lepiej wyglądał.
Wprowadzenie do Angular 2
32/61
1. Dodanie pól do klasy komponentu
Pierwsza zmiana to dodanie dwóch pól do klasy i wyświetlenie ich w szablonie:
folderApp/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>{{title}}</h1><h2>{{hero}}</h2>'
})
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
hero = 'Jan Paweł II';
}
Projekt powinien się automatycznie przekompilować.
Widok pokazuje pola naszego komponentu.
Wprowadzenie do Angular 2
33/61
2. Dodanie klasy zamiast prostych pól
Druga zmiana to dodanie klasy zamias prostego pola.
W szablonie wyświetlamy pola klasy:
folderApp/app.component.ts
import { Component } from '@angular/core';
export class Bohater {
id: number;
name: string;
}
@Component({
selector: 'my-app',
template: '<h1>{{title}}</h1><h2>{{hero.name}}</h2>'
})
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
hero: Bohater = {id:12, name:'Jan Paweł II'};
}
Wprowadzenie do Angular 2
34/61
3. Powiększenie szablonu
Trzecia zmiana to powiększenie szablonu, korzystamy z odwrotnego apostrofu (‘):
folderApp/app.component.ts
import { Component } from '@angular/core';
export class Bohater {
id: number;
name: string;
}
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Informacje szczegółowe o {{hero.name}}!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div><label>nazwa: </label>{{hero.name}}</div>
‘
})
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
hero: Bohater = {id:12, name:'Jan Paweł II'};
}
Wprowadzenie do Angular 2
35/61
4. Dodanie pola edycji w szablonie
Mała zmiana w szablonie, dodajemy pole do edycji nazwy naszego bohatera:
folderApp/app.component.ts
import { Component } from '@angular/core';
export class Bohater { id: number; name: string; }
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Informacje szczegółowe o {{hero.name}}!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>nazwa: </label>
<input value="{{hero.name}}" placeholder="name">
</div>
‘
})
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
hero: Bohater = {id:12, name:'Jan Paweł II'};
}
Wprowadzenie do Angular 2
36/61
5. Dwukierunkowe wiązanie danych
Pobieranie nazwy bohatera z użyciem dwukierunkowego wiązania danych:
folderApp/app.component.ts
import { Component } from '@angular/core';
export class Bohater { id: number; name: string; }
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Informacje szczegółowe o {{hero.name}}!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>nazwa: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
‘
})
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
hero: Bohater = {id:12, name:'Jan Paweł II'};
}
Wprowadzenie do Angular 2
37/61
6. Dodanie tablicy bohaterów
Dodanie tablicy bohaterów i dodanie pola z nimi do klasy:
folderApp/app.component.ts
....
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
hero: Bohater = {id:12, name:'Jan Paweł II'};
public heroes = BOHATEROWIE;
}
var BOHATEROWIE: Bohater[] = [
{id:11, name:"Jan III Sobieski"},
{id:12, name:"Jan Paweł II"},
{id:13, name:"Władysław II Jagiełło"},
{id:14, name:"św. Faustyna Kowalska"},
{id:15, name:"Jurand ze Spychowa"},
{id:16, name:"Andrzej Kmicic"},
{id:17, name:"Judyta"},
{id:18, name:"św. Małgorzata Maria Alacoque"}
];
Wprowadzenie do Angular 2
38/61
7. Przygotowanie szablonu dla listy bohaterów
Dodajemy nagłówek i listę wypunktowaną - szablon dla listy bohaterów:
folderApp/app.component.ts
...
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Moi bohaterowie</h2>
<ul>
<li>
<!-- tutaj będzie lista bohaterów -->
</li>
</ul>
<h2>Informacje szczegółowe o {{hero.name}}!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>nazwa: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
‘
})
...
Wprowadzenie do Angular 2
39/61
8. Dodanie pętli dla listy bohaterów - ngFor
Dodane pętli - dyrektywa *ngFor:
folderApp/app.component.ts
...
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Moi bohaterowie</h2>
<ul>
<li *ngFor="let hero of heroes">
<span>{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<h2>Informacje szczegółowe o {{hero.name}}!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>nazwa: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
‘
})
...
Wprowadzenie do Angular 2
40/61
Wynik działania aplikacji
Wprowadzenie do Angular 2
41/61
9. Obsługa wyboru bohatera - click event
Dodajemy atrybut (click) z przypisaną mu metodą onSelect() klasy
FirstComponent:
folderApp/app.component.ts
...
<h2>Moi bohaterowie</h2>
<ul>
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
<span>{{hero.id}}</span> {{hero.name}}
</li>
</ul>
...
Wprowadzenie do Angular 2
42/61
10. Obsługa wyboru bohatera - dodanie pola i metody
Do FirstComponent dodajemy pole selectedHero oraz metodę onSelect():
folderApp/app.component.ts
...
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
selectedHero: Bohater;
onSelect(hero: Bohater) { this.selectedHero = hero; }
// hero: Bohater = {id:12, name:'Jan Paweł II'};
public heroes = BOHATEROWIE;
}
...
Wprowadzenie do Angular 2
43/61
11. Obsługa wyboru bohatera - poprawki zmiennych i ngIf
W szablonie dostosowujemy nazwy do zmian w FirstComponent, dodajemy ngIf:
folderApp/app.component.ts
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Moi bohaterowie</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
<span>{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<div *ngIf="selectedHero">
<h2>Informacje szczegółowe o {{selectedHero.name}}!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>nazwa: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name">
</div>
</div>
‘
})
Wprowadzenie do Angular 2
44/61
Wynik działania aplikacji - lista po zmianach
Wprowadzenie do Angular 2
45/61
Gdzie jesteśmy - obsługa wyboru bohatera
Gdzie jesteśmy?
Mamy tylko jeden komponent - FirstComponent zawierający:
tytuł naszej aplikacji,
wybranego bohatera,
metodę do wyboru bohatera,
listę bohaterów,
tablica z bohaterami znajduje się w tym samym pliku,
mamy też klasę odpowiedzialną za pojedynczego bohatera - również
w tym samym pliku,
Funkcjonalność:
wyświetlanie listy bohaterów,
możliwć edycji wybranego bohatera.
Wprowadzenie do Angular 2
46/61
12. Osobny komponent do wyświetlania szczegółów
Przechowywanie w jednym komponencie obsługi listy bohaterów i
wyświetlania szczegółów o nich narusza zasadę pojedynczej
odpowiedzialności.
Dzielimy tę funkcjonalność na dwa osobne komponenty.
Tworzymy komponent HeroDetailComponent, wersja początkowa:
folderApp/hero-detail.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'my-hero-detail',
})
export class HeroDetailComponent {
}
Wprowadzenie do Angular 2
47/61
13. Osobny komponent z szablonem
Do komponentu HeroDetailComponent przenosimy kod szablonu
odpowiadający za szczegóły wybranego bohatera:
folderApp/hero-detail.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'my-hero-detail',
template: ‘
<div *ngIf="hero">
<h2>Informacje szczegółowe o {{hero.name}}!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>nazwa: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
</div>
‘
})
export class HeroDetailComponent { }
Zmiana selectedHero na hero.
Wprowadzenie do Angular 2
48/61
14. Klasa Bohater w osobnym pliku
Przenosimy klasę Bohater do osobnego pliku - będzie potrzebna w
obu komponentach:
folderApp/bohater.ts
export class Bohater {
id: number;
name: string;
}
W obu komponentach dodajemy import utworzonej klasy:
import { Bohater } from './bohater';
Do klasy HeroDetailComponent dodajemy pole hero (@Input):
folderApp/hero-detail.component.ts
...
export class HeroDetailComponent {
@Input()
hero: Bohater;
}
Wprowadzenie do Angular 2
49/61
Pole hero jako Input
Komponent HeroDetailComponent musi wiedzieć, którego bohatera
dane ma wyświetlać.
Informacje o tym posiada komponent nadrzędny: FirstComponent.
Chcemy wyświetlić szczegóły wybranego bohatera.
Komponent nadrzędny wiąże pole selectedHero z polem hero
komponentu podrzędnego:
Pole docelowe, w nawiasach [ ] po lewej stronie znaku = musi być
wejściowym (input):
folderApp/app.component.ts (fragment szablonu)
...
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
...
Wprowadzenie do Angular 2
50/61
15. FirstComponent po zmianach
FirstComponent z importem drugiego komponentu i zmienionym szablonem
zawierającym metadane o nowym komponencie:
folderApp/app.component.ts (fragment)
import { Component } from '@angular/core';
import { HeroDetailComponent } from './hero-detail.component';
import { Bohater } from './bohater';
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Moi bohaterowie</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
<span>{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
‘,
directives: [HeroDetailComponent]
})
...
Wprowadzenie do Angular 2
51/61
Tablica directives
Przeglądarka ignoruje nieznane znaczniki HTML - tak samo Angular.
Sam import komponentu HeroDetailComponent nie wystarczy.
Należy jeszcze poinformować o tym Angular!
Czynimy to dodając nazwę komponentu do tablicy directives.
folderApp/app.component.ts (konfigurowanie kompoentu)
@Component({
selector: 'my-app',
template: ‘
<h1>{{title}}</h1>
<h2>Moi bohaterowie</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
<span>{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
‘,
directives: [HeroDetailComponent]
})
...
Wprowadzenie do Angular 2
52/61
15. FirstComponent po zmianach II
Klasa FirstComponent jako nadrzędny komponent:
folderApp/app.component.ts (fragment)
...
export class FirstComponent {
title = 'Wprowadzenie o bohaterach';
selectedHero: Bohater;
onSelect(hero: Bohater) { this.selectedHero = hero; }
public heroes = BOHATEROWIE;
}
var BOHATEROWIE: Bohater[] = [
{id:11, name:"Jan III Sobieski"},
{id:12, name:"Jan Paweł II"},
{id:13, name:"Władysław II Jagiełło"},
{id:14, name:"św. Faustyna Kowalska"},
{id:15, name:"Jurand ze Spychowa"},
{id:16, name:"Andrzej Kmicic"},
{id:17, name:"Judyta"},
{id:18, name:"św. Małgorzata Maria Alacoque"}
];
Wprowadzenie do Angular 2
53/61
16. Tworzenie usługi
Nazwa pliku usługi kończy się na *.service.ts - taka konwencja.
Eksportujemy klasę HeroService - usługa z listą bohaterów.
Importujemy funkcję Injectable i stosujemy ją korzystając z wzorca
dekorator.
Dzięki temu Angular śledzi zależności tej usługi od innych - emituje
metadane o naszej usłudze.
Nawet, jeśli nasza usługa nie ma żadnych zależności, dobrze jest od
początku dodawać dekorator @Injectable().
folderApp/bohater.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class HeroService {
}
Wprowadzenie do Angular 2
54/61
17. Imitowane dane naszych bohaterów
Przenosimy dane z pliku app.component.ts do osobnego pliku, specjalnie
dla nich.
folderApp/dane-bohaterowie.ts
import { Bohater } from './bohater';
export var BOHATEROWIE: Bohater[] = [
{id:11, name:"Jan III Sobieski"},
{id:12, name:"Jan Paweł II"},
{id:13, name:"Władysław II Jagiełło"},
{id:14, name:"św. Faustyna Kowalska"},
{id:15, name:"Jurand ze Spychowa"},
{id:16, name:"Andrzej Kmicic"},
{id:17, name:"Judyta"},
{id:18, name:"św. Małgorzata Maria Alacoque"}
];
W pliku app.component.ts pole z listą bohaterów zostawiamy puste:
folderApp/app.component.ts
heroes: Bohater[];
Wprowadzenie do Angular 2
55/61
18. Metoda dostępowa
Użytkownik usługi nie wie z jakiego źródła są dane.
Dane mogą pochodzić z Web Serwisu, z lokalnego pliku albo być imitowane.
To jest piękno korzystania z usług!
Usługa odpowiada za dostęp do danych.
W każdej chwili można zmienić sposób dostępu - zmiany są tylko w tej
jednej usłudze.
folderApp/bohater.service.ts
import { Injectable } from '@angular/core';
import { BOHATEROWIE } from './dane-bohaterowie';
@Injectable()
export class HeroService {
getHeroes() {
// return BOHATEROWIE;
return Promise.resolve(BOHATEROWIE);
}
}
Wprowadzenie do Angular 2
56/61
Wykorzystanie usługi
Importujemy potrzebną nam usługę - możemy się do niej odwołać w
kodzie.
Jak Angular utworzy tę usługę?
Nie tworzymy jej samodzielnie, nie korzystamy z new ponieważ:
nasz komponent musiał by wiedzieć jak utworzyc usługę; zmiana
konstruktora usługi wymagała by zmiany jego wywołania w wielu
miejscach...
samodzielne tworzenie usługi w każdym komponencie utowrzy wiele jej
instancji ... co jeśli będzie potrzebna tylko jedna współdzielona?
wiąże nas to z konkretną implementacją HeroService - ciężko przejść
na inne scenariusze, zmieniać dane do testowania...
Dlatego też stosujemy wstrzykiwanie zależności.
Wprowadzenie do Angular 2
57/61
19. Wykorzystanie usługi
folderApp/app.component.ts
...
import { HeroService } from './bohater.service';
import { OnInit } from '@angular/core';
@Component({
...
providers: [HeroService]
})
export class AppComponent implements OnInit {
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
title = 'Wprowadzenie o bohaterach';
selectedHero: Bohater;
onSelect(hero: Bohater) { this.selectedHero = hero; }
heroes: Bohater[]; // public heroes = BOHATEROWIE;
getHeroes() {
// this.heroes = this.heroService.getHeroes();
this.heroService.getHeroes().then(heroes => this.heroes = heroes);
}
}
Wprowadzenie do Angular 2
58/61
Wykorzystanie usługi
Stosujemy wstrzykiwanie zależności.
Zamiast wykorzystania operatora new do komponentu dodamy:
konstruktor z parametrem potrzebnej usługi:
parametr tworzy automatycznie prywatne pole heroService,
pole heroService zostanie rozpoznane jako klasa HeroService, która
jest tworzona przez wstrzykiwanie zależności,
Angular będzie wiedział, aby dostarczyć instancję usługi, przy
tworzeniu komponentu,
metadane z listą dostawców (providers) potrzebnych usług:
informują Injector jak utworzyć usługę HeroService,
usługę należy dodać do listy dostawców (providers) w metadanych
konfigurujących komponent,
tablica providers informuje Angular, że ma utworzyć nową instancję
usługi przy tworzeniu komponentu.
Wprowadzenie do Angular 2
59/61
Wstawki programowe - ngOnInit
Pobieranie danych z usługi powinno się odbywać automatycznie.
Gdzie dodać kod odczytu danych z usługi?
Nie dodajemy logiki do konstruktora, szczególnie takiej, która łączy
się z serwerem.
Wczytywanie danych powinno odbywać się już na utworzonym
komponencie.
Wykorzystamy wstawki programowe dla cyklu życia komponentu ngOnInit.
Angular sam wywoła odpowiedną metodę przy określonym stanie
komponentu.
Wprowadzenie do Angular 2
60/61
Ź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
Wprowadzenie do Angular 2
61/61

Podobne dokumenty