57
Data Flow Patterns in Angular 2 Sebastian Müller - adesso AG EnterJS - 15.06.2016

Data Flow Patterns in Angular 2 - Sebastian Müller

Embed Size (px)

Citation preview

Data Flow Patterns in Angular 2Sebastian Müller - adesso AG

EnterJS - 15.06.2016

Sebastian Müller@Sebamueller

Angular 2

ComponentsComponent Tree

Component Tree

Application

MainNavigation UsersList

UsersListEntry UsersListEntry

Die erste Appimport{Component}from'@angular/core';import{bootstrap}from'@angular/platform-browser-dynamic';

@Component({selector:'my-app',//cssselectortemplate:`<h1>{{title}}</h1>`})exportclassAppComponent{title:string='my-appworks!';}

bootstrap(AppComponent);

Die erste App<html> <head> … </head> <body> <my-app>Loading...</my-app>

… </body> </html>

Component Kommunikation

User App

UserApp

UserCard

user={username:'admin',email:'[email protected]'};

user

Inputs

UserApp Component

UserApp

UserCard

import{Component}from'@angular/core';import{bootstrap}from'@angular/platform-browser-dynamic';import{UserCard}from'./user-card.component';

@Component({selector:'my-app',directives:[UserCard],template:`<user-card[cardDetails]="user"></user>`})exportclassUserApp{user={username:'admin',email:'[email protected]'};}

bootstrap(UserApp);

UserCard Component

UserApp

UserCard

import{Component,Input}from'@angular/core';

@Component({selector:'user-card',template:`<div><h2>Username:{{cardDetails.username}}</h2><h3>E-Mail:{{cardDetails.email}}</h2></div>`})exportclassUserCard{@Input()cardDetails;}

RxJS 5 Reactive Extensions

Was ist RxJS?• Library für reaktive Programmierung im

JavaScript Bereich

• Open Source - Version 5 aktuell im Beta Status

• Wird führend von Netflix entwickelt(Ben Lesh - @BenLesh)

• Observable als wichtigster Baustein für Reaktive Programmierung

Was sind Observables?

Synchron / Pull Asynchron / Push

Ein

Valu

eM

ehre

re V

alue

sFunctions

Iterators

Promises

Observables

„Lodash for async data“

Observableimport{Observable}from'rxjs/Observable';

varobservable=Observable.create(functionsubscribe(observer){vari=0;setInterval(()=>{observer.next(i++);},1000);}); Lazyvarsubscription=observable.subscribe(functionnext(value){console.log(value);});

123

Observable Subscriptionimport{Observable}from'rxjs/Observable';

varobservable=Observable.create(functionsubscribe(observer){vari=0;varid=setInterval(()=>{observer.next(i++);},1000);

returnfunctionunsubscribe(){console.log('unsubscribe');

clearInterval(id);};});varsubscription=observable.subscribe(functionnext(value){console.log(value);});

setTimeout(()=>{subscription.unsubscribe();

},2500);

12unsubscribe

subscribe()

myPromise.then(function(value){console.log('success',value);},function(err){console.log('error',err);});

myObservable.subscribe(function(value){console.log('success',value);},function(err){console.log('error',err);});

Promise

Observable

subscribe()

myObservable.subscribe(function(value){console.log('success',value);},function(err){console.log('error',err);},function(){console.log('completed');});

varmyObservable=Observable.create((observer)=>{observer.next(1);setTimeout(()=>{observer.next(2);observer.complete();},1000);});

success1success2completed

RxJS Operators

map Operator

myObservable.subscribe(function(value){console.log('success',value);});

success0success2

import{Observable}from'rxjs/Observable';import'rxjs/add/operator/map';

varmyObservable=Observable.create((observer)=>{vari=0;setInterval(()=>{observer.next(i++);},1000);}).map((value)=>value*2);

success4

Weitere Operators• filter

• pluck

• groupBy

• scan (reduce)

• zip

• throttle

• …

Observables vs Promises

Promise Observable / RxJS

Liefert nur einen Wert zurück Liefert 0-n Werte

Kann nicht abgebrochen werden*

Kann abgebrochen werden - unsubscribe()

Keine OperatorsBietet Operators für

Datentransformationen/Filterung/etc.

*Aktuell in Diskussion

RxJS 5 ist fest integriert

Outputs

User App

UserApp

UserCard

user={username:'admin',email:'[email protected]'};

user

<user-card[cardDetails|="user"></user-card>

sendEmail

<user-card[cardDetails]="user"(sendEmail)="showMailForm($event)"></user-card>

EventEmitter

UserCard Componentimport{Component,Input,Output,EventEmitter}from'@angular/core';

@Component({selector:'user-card',template:`<div><h2>Username:{{cardDetails.username}}</h2><h3(click)="emailClicked()">E-Mail:{{cardDetails.email}}</h2></div>`})exportclassUserCard{@Input()cardDetails;@Output()sendEmail:EventEmitter<string>=newEventEmitter<string>();

emailClicked(){this.sendEmail.emit(this.cardDetails.email);//Observable}}

Component Tree

Application

MainNavigation UsersList

UsersListEntry UsersListEntry

Unidirectional Data Flow

Async Pipe

Async Pipeimport{Component}from'@angular/core';import{bootstrap}from'@angular/platform-browser-dynamic';import{Observable}from'rxjs/Observable';

@Component({selector:'my-app',template:`<h1>{{counter|async}}</h1>`})exportclassAppComponent{counter:Observable<number>=Observable.create((observer)=>{vari=0;varid=setInterval(()=>{observer.next(i++);},1000);return()=>{clearInterval(id);};});}

Form Fields

valueChanges@Component({selector:'my-app',template:`<form><input[ngFormControl]="myInput"></form>{{result|async}}`})exportclassAppComponent{myInput:Control=newControl();result:Observable<any>;

ngOnInit(){this.result=this.myInput.valueChanges.map((value)=>value*2);}}

@angular/http

@angular/http• XHR Client

• API basiert auf Observables

• Eigenständiges Package

• Mocking Features

@angular/httpimport{Component}from'@angular/core';import{Http,Response}from'@angular/http';

@Component({selector:'my-comp',template:`{{data|async}}`

})classMyComponent{data:string;constructor(privatehttp:Http){}ngOnInit(){this.data=this.http.get('/my/api').map((r:Response)=>r.json());}}

Observables als Input

Observables als Input

import{Component,Input}from'@angular/core';import{Observable}from'rxjs/Observable';

@Component({selector:'stock-info',template:`Preis:<b>{{stockPrice|async}}</b>`})exportclassStockComponent{@Input()stockPrice:Observable<number>;}

<stock-info[stockPrice]="myObservable"></stock-info>

Performance

Change Detection in Angular 2 ist sehr schnell

ChangeDetectionStrategy

Change Detection

Application

UserProfile Main Navigation

NavEntry NavEntry

user={username:'admin',email:'[email protected]'};

navEntries=[{name:'a'},{name:'a'}]

navEntriesuser

[email protected]@abc.de

user={username:'admin',email:'[email protected]'};

ChangeDetectionStrategy.OnPush

a === b

Change Detection

Application

UserProfile(OnPush)

Main Navigation(OnPush)

NavEntry NavEntry

user={username:'admin',email:'[email protected]'};

navEntries=[{name:'a'},{name:'a'}]

navEntriesuser

[email protected]

user={username:'admin',email:'[email protected]'};

👎

Immutable.js

+Angular 2

Immutable.js• Library für Immutable Data Structures

• Open Source Projekt von Facebook

• Im React Bereich weit verbreitet

• TypeScript Type Definitions vorhanden

• Unterstützt:

• Maps

• Sets

• Lists (Arrays)

• u.v.m.

ö

varbook=Immutable.Map({title:'Mybooktitle'});

varbook2=book.set('title','newtitle');

console.log(book===book2);//falseconsole.log(book2.toObject());//{title:'newtitle’}console.log(book.toObject());//{title:'Mybooktitle'}

DEMO

Change Detection

Application

UserProfile(OnPush)

Main Navigation(OnPush)

NavEntry NavEntry

user={username:'admin',email:'[email protected]'};

navEntries=[{name:'a'},{name:'a'}]

navEntriesuser

[email protected]@abc.de

user=user.set('email','[email protected]')

"

Talk:Angular 2 Change Detection erklärtPascal Precht

Fazit

Fazit• Angular 2 bietet viele nützliche Wege zur

Kommunikation

• Einarbeitung in RxJS kostet viel Zeit

• Aber es lohnt sich!

• Angular 2 Change Detection ist sehr schnell

• ChangeDetectionStrategy.OnPush wenn möglich einsetzen

Danke!

EnterJS - 15.06.2016 @Sebamueller