devfest 2016 - angular 2 workshop · devfest 2016 - angular 2 workshop milan lempera víťa plšek...

51
DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Upload: others

Post on 03-Jun-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

DEVFEST 2016 -ANGULAR 2 WORKSHOP

Milan Lempera  

Víťa Plšek  

Matěj Horák

 @milanlempera

 @vitaplsek

 @horakmat

angular.cz

Page 2: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

O nás

Milan Lempera 

php, javascript, clojure(script)

@milanlempera

Víťa Plšek 

java, javascript

@vitaplsek

angular.cz

0‐1

Page 3: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

O nás

Matěj Horák 

java, javascript

@horakmat

Víťa Plšek 

java, javascript

@vitaplsek

0‐2

Page 4: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

ANGULAR.CZ/DEVFEST-2016 0‐3

Page 5: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

PART 1 1‐0

Page 6: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Angular JS

Angular 1.Xsince 2009

Angular 2since 2016

1‐1

Page 7: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

1‐2

Page 8: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

1‐3

Page 9: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

JavaScript vs TypeScriptfunction area(r) { return Math.PI * r * r; } let myNumber = 2; let myString = '2' area(myNumber); // Ok area(myString); // Ok

function area(r: number): number { return Math.PI * r * r; } let myNumber = 2; let myString = '2' area(myNumber); // Ok area(myString); // ERROR

1‐4

Page 10: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Arrow functionslet area = r => Math.PI * r * r;

let area = (r: number) => Math.PI * r * r;

1‐5

Page 11: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

TypeScriptlet myNumber = 2; // typ bude odvozen

let otherNumber:number = 2;

myNumber = 'someString'; // ERROR

otherNumber = 'someString'; // ERROR

// definice typů pole

let arrayOfNumbers: number[];

// generika

let numbers: Set<number> = new Set();

numbers.add(1); // OK

numbers.add("a"); // ERROR

1‐6

Page 12: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

TypeScript - Classclass Greeter { private message: string;

constructor(message: string) { this.message = message; }

greet() { return "Hello, " + this.message; }}

let greeter = new Greeter("world");

1‐7

Page 13: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

TypeScript - Classclass Greeter {

constructor(private message: string) { }

greet() { return "Hello, " + this.message; }}

let greeter = new Greeter("world");

1‐8

Page 14: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

TypeScript - Interfaceinterface Speaker { id?: number; name: string; }

"structural subtyping" / "duck typing"záleží jen na struktuře objektu

let speaker1: Speaker = { // OK id: 1, name: 'Petr Novák' };

let speaker2: Speaker = { // OK - id není povinné name: 'Petr', surname: 'Novák' };

let speaker3: Speaker = { // ERROR - neobsahuje name id: 11, surname: 'Novák' };

1‐9

Page 15: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

TypeScript - Dekorátoryfunction enableLogging(target) { target.loggingEnable = true; }

@enableLogging class Calculator { }

const calculator = new Calculator(); calculator.loggingEnable // true

můžete dekorovat i vlastnos� a metody

1‐10

Page 16: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Struktura aplikaceAngular staví aplikaci jako strom komponent

app‐root

app‐task‐listapp‐task‐detailapp‐task‐infoapp‐task‐ac�ons

1‐11

Page 17: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Angular CLIdevstack

scafolding

Vygenerování komponentyng generate component tasks/task-list

installing component create src/app/tasks/task-list/task-list.component.css create src/app/tasks/task-list/task-list.component.html create src/app/tasks/task-list/task-list.component.spec.ts create src/app/tasks/task-list/task-list.component.ts

1‐12

Page 18: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Komponentaimport { Component, OnInit } from '@angular/core';

@Component({ selector: 'app-task-list', templateUrl: './task-list.component.html', styleUrls: ['./task-list.component.css'] }) export class TaskListComponent implements OnInit {

constructor() { }

ngOnInit() { }

}

Použití komponenty v šabloně<app-task-list></app-task-list>

1‐13

Page 19: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Attributy a metody komponentyimport { Component, OnInit } from '@angular/core'; import { Task } from './task';

@Component({ selector: 'app-task-list', templateUrl: './task-list.component.html', styleUrls: ['./task-list.component.css'] }) export class TaskListComponent implements OnInit {

tasks: Task[]; selectedTask: Task;

getTotalEstimation() { return ... }

...

}

1‐14

Page 20: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Šablona komponentyInterpolace

<h1>{{selectedTask.title}}</h1>

<span>Total Estimation: {{getTotalEstimation()}}</span>

Cykly, podmínky<ul> <li *ngFor="let task of tasks">

{{task.title}} <span *ngIf="task.isOverdue">Overdue !</span>

</li> </ul>

1‐15

Page 21: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Event binding<button type="button" (click)="upVote(task)">Vote</button>

<span [class]="task.type"></span>

<input type="text" [(ngModel)]="task.title" />

Také u vlastních komponent<app-task-list [tasks]="overdueTasks" (onUpVote)="voteForTask($event)"> </app-task-list>

1‐16

Page 22: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Rozhraní komponenty@Component({ selector: 'app-task-list', templateUrl: './task-list.component.html', styleUrls: ['./task-list.component.css'] }) export class TaskListComponent implements OnInit {

@Input() tasks: Task[]; @Output() onUpVote = new EventEmitter<Task>();

upVote(task) { this.onUpVote.emit(task); }

...}

<app-task-list [tasks]="overdueTasks" (onUpVote)="voteForTask($event)"> </app-task-list>

1‐17

Page 23: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Vyzkoušejte si to 1‐18

Page 24: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

PART 2 2‐0

Page 25: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

ModulyModuly vystavují komponenty a udávají závislost na jiné moduly

@NgModule({ declarations: [ AppComponent, TaskDetailComponent, TaskListComponent, Error404Component ],

imports: [ BrowserModule, HttpModule, ],

bootstrap: [AppComponent] }) export class AppModule {}

2‐1

Page 26: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Routingtransparentní chování aplikace v prostředí webu

stav a URL adresa jsou vzájemně provázané

historie (vpřed, zpět)možnost poslat/uložit URL

2‐2

Page 27: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Router ModuleRouterModule.forRoot([ {path: '', component: TaskListComponent}, {path: 'task/:id', component: TaskDetailComponent}, {path: '**', component: Error404Component} ] )

Vykreslení v šabloně<html> <head> </head> <body>

<router-outlet></router-outlet>

</body> </html>

2‐3

Page 28: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Moduly a routing@NgModule({ imports: [ RouterModule.forRoot([ {path: '', component: TaskListComponent}, {path: 'task/:id', component: TaskDetailComponent}, {path: '**', component: Error404Component} ] ) ], exports: [ RouterModule ] }) export class AppRoutingModule {}

2‐4

Page 29: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Moduly a routing@NgModule({ declarations: [ AppComponent, TaskDetailComponent, TaskListComponent, Error404Component ],

imports: [ BrowserModule, HttpModule, AppRoutingModule // routing modul ],

bootstrap: [AppComponent] }) export class AppModule {}

2‐5

Page 30: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Přechod mezi routami<a routerLink="/tasks">Seznam</a>

<a [routerLink]="['task', task.id]">Detail</a>

2‐6

Page 31: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Injectablesimport { Task } from "./task";import { Injectable } from "@angular/core";

@Injectable() export class TaskDataService {

getTasks(): Task[]{ ... }

}

2‐7

Page 32: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Začlenení do modulu@NgModule({ declarations: [ AppComponent, TaskDetailComponent, TaskListComponent, Error404Component ],

imports: [ BrowserModule, HttpModule, AppRoutingModule ],

providers: [TaskDataService], // injektovatelná závislost

bootstrap: [AppComponent] }) export class AppModule {}

2‐8

Page 33: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Injektáž do komponentyexport class TaskListComponent implements OnInit {

constructor(private taskDataService: TaskDataService) { }

ngOnInit(): void { this.tasks = this.taskDataService.getTasks(); }

...}

2‐9

Page 34: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Získání parametrů routyexport class TaskDetailComponent implements OnInit {

constructor(private route: ActivatedRoute) { }

ngOnInit(): void { let idParam = this.route.snapshot.params['id']; let id = parseInt(idParam);

... }

...}

2‐10

Page 35: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Asynchronní datafunction onSearch(text) { let url = '/api/?q=' + text; $http .get(url) .then(function(response) { showData(response.data); }); }

onSearch('abc')

httpPromise

thenshowData(response.data)

then

Server

2‐11

Page 36: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Asynchronní datalet search = new Subject() .map((text) => '/api/?q=' + text) .flatMap((url) => $http.get(url)) .subscribe((response) { showData(response.data); }) function onSearch(text) { return search.next(text); }

search

text -> url

url -> promise -> response

response ->

showData(response.data)

abc

onSearch('abc')

/api/?q=abc

Request

Response

onSearch('def')

def

2‐12

Page 37: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Observable + subscribe@Component({ ...}) export class SomeComponent implements OnInit {

titleObservable: Observable<string>;

title: string;

ngOnInit() {

this.titleObservable .subscribe((title) => this.title = title); }

}

{{ title }}

2‐13

Page 38: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Pipe@Component({ ...}) export class SomeComponent {

title: string = "Angular" }

{{ title }} -> Angular

{{ title | uppercase }} -> ANGULAR

vestavěné: date, uppercase, lowercase, currency, percent, async

2‐14

Page 39: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Observable + async pipe@Component({ ...}) export class SomeComponent implements OnInit {

titleObservable: Observable<string>;

}

{{ titleObservable | async }}

2‐15

Page 40: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Vyzkoušejte si to 2‐16

Page 41: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

PART 3 - BONUS 3‐0

Page 42: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Angular 2 Formstemplate based

podobné jako v Angular 1

reac�ve

změny data jako Observable

3‐1

Page 43: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Angular 2 Reactive Forms@Component() export class SearchComponent implements OnInit {

searchControl = new FormControl();

ngOnInit() { this.searchControl.valueChanges.subscribe(value => { // do something with value here }); } }

<input type="search" [formControl]="seachControl">

3‐2

Page 44: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Observables - operátory 3‐3

Page 45: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

RxJS .map

rxmarbles.com

3‐4

Page 46: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

RxJS .flatMap

Podobné jako map, ale místo Observable/Promise vrací rovnou hodnoty,

nemusíte tedy zanořovat subscribe/then v map.

reac�vex.io/documenta�on/operators/flatmap.html

3‐5

Page 47: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

RxJS .startWith

rxmarbles.com

3‐6

Page 48: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

RxJS .debounce

rxmarbles.com

3‐7

Page 49: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

RxJS .distinctUntilChanged

rxmarbles.com

a mnoho dalších ‐ reac�vex.io/rxjs/manual/overview.html#categories‐of‐

operators

3‐8

Page 50: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

Vyzkoušejte si to 3‐9

Page 51: DEVFEST 2016 - ANGULAR 2 WORKSHOP · DEVFEST 2016 - ANGULAR 2 WORKSHOP Milan Lempera Víťa Plšek Matěj Horák @milanlempera @vitaplsek @horakmat angular.cz

ANGULAR.CZ/DEVFEST-2016 4‐0