93
Go Beast Mode with Realtime Reactive Interfaces in Angular and Firebase

Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Embed Size (px)

Citation preview

Page 1: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Go Beast Mode with Realtime Reactive Interfacesin Angular and Firebase

Page 2: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

State management

Page 3: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Controlling flow

Page 4: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Code volume

Page 5: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Enter Observables

Page 6: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

return this.http.get(this.URLS.FETCH) .map(res => res.json()) .toPromise();

Problem solved!

Page 7: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Observables give us a powerful way to encapsulate, transpor t and transform data from user interactions to create powerful and immersive experiences.

Page 8: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Encapsulate Transport Transform

Page 9: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Encapsulate Transport Transform

Page 10: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Encapsulate Transport Transform

Page 11: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Iterator Pattern Observer Pattern

State Communication

Page 12: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Communicate state over time

Page 13: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Observable stream

Page 14: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Values over time

SINGLE MULTIPLE

SYNCHRONOUS Function Enumerable

ASYNCHRONOUS Promise Observable

Page 15: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Value consumption

SINGLE MULTIPLE

PULL Function Enumerable

PUSH Promise Observable

Page 16: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

But observables are hard!!!

Page 17: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

The Observable Stream

Page 18: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

input output

Page 19: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

output input

Page 20: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

The Basic Sequence

Page 21: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

final input

initial output

magic

Page 22: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

subscribe

event

operators

Page 23: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('btn') btn;message: string;ngOnInit() { Observable.fromEvent(this.getNativeElement(this.btn), 'click') .subscribe(result => this.message = 'Beast Mode Activated!');}getNativeElement(element) { return element._elementRef.nativeElement;}

Page 24: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('btn') btn;message: string; ngOnInit() { Observable.fromEvent(this.getNativeElement(this.btn), 'click') .subscribe(result => this.message = 'Beast Mode Activated!');}getNativeElement(element) { return element._elementRef.nativeElement;}

Initial output

Page 25: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('btn') btn;message: string; ngOnInit() { Observable.fromEvent(this.getNativeElement(this.btn), 'click') .subscribe(event => this.message = 'Beast Mode Activated!');}getNativeElement(element) { return element._elementRef.nativeElement;}

Final input

Page 26: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('btn') btn;message: string; ngOnInit() { Observable.fromEvent(this.getNativeElement(this.btn), 'click') .map(event => 'Beast Mode Activated!') .subscribe(result => this.message = result);}getNativeElement(element) { return element._elementRef.nativeElement;}

Everything in between

Page 27: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('btn') btn;message: string; ngOnInit() { Observable.fromEvent(this.getNativeElement(this.btn), 'click') .filter(event => event.shiftKey) .map(event => 'Beast Mode Activated!') .subscribe(result => this.message = result);}getNativeElement(element) { return element._elementRef.nativeElement;}

Everything in between

Page 28: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

BASIC SEQUENCE

Page 29: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

How do we preserve state in a stream?

Page 30: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

<button #right>Right</button><div class="container"> <div #ball class="ball" [style.left]="position.x + 'px'" [style.top]="position.y + 'px'"> </div></div>

Page 31: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('right') right;position: any;ngOnInit() { Observable .fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10) .startWith({x: 100, y: 100}) .scan((acc, curr) => { return { y: acc.y, x: acc.x + curr}}) .subscribe(result => this.position = result);}

Page 32: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('right') right;position: any; ngOnInit() { Observable .fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10) .startWith({x: 100, y: 100}) .scan((acc, curr) => { return { y: acc.y, x: acc.x + curr}}) .subscribe(result => this.position = result);}

Page 33: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('right') right;position: any; ngOnInit() { Observable .fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10) .startWith({x: 100, y: 100}) .scan((acc, curr) => { return { y: acc.y, x: acc.x + curr}}) .subscribe(result => this.position = result);}

Page 34: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('right') right;position: any; ngOnInit() { Observable .fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10) .startWith({x: 100, y: 100}) .scan((acc, curr) => { return { y: acc.y, x: acc.x + curr}}) .subscribe(result => this.position = result);}

Page 35: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

MAINTAINING STATE

Page 36: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

What if we have more than one stream?

Page 37: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('left') left;@ViewChild('right') right;position: any;ngOnInit() { const left$ = Observable.fromEvent(this.getNativeElement(this.left), 'click') .map(event => -10); const right$ = Observable.fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10); Observable.merge(left$, right$) .startWith({x: 100, y: 100}) .scan((acc, curr) => { return { y: acc.y, x: acc.x + curr}}) .subscribe(result => this.position = result);}

Page 38: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('left') left;@ViewChild('right') right;position: any;ngOnInit() { const left$ = Observable.fromEvent(this.getNativeElement(this.left), 'click') .map(event => -10); const right$ = Observable.fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10); Observable.merge(left$, right$) .startWith({x: 100, y: 100}) .scan((acc, curr) => { return { y: acc.y, x: acc.x + curr}}) .subscribe(result => this.position = result);}

Page 39: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

MERGING STREAMS

Page 40: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

What can we put in a stream?

Page 41: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

increment(obj, prop, value) { return Object.assign({}, obj, {[prop]: obj[prop] + value})}decrement(obj, prop, value) { return Object.assign({}, obj, {[prop]: obj[prop] - value})}ngOnInit() { const leftArrow$ = Observable.fromEvent(document, 'keydown') .filter(event => event.key === 'ArrowLeft') .mapTo(position => this.decrement(position, 'x', 10)); const rightArrow$ = Observable.fromEvent(document, 'keydown') .filter(event => event.key === 'ArrowRight') .mapTo(position => this.increment(position, 'x', 10)); Observable.merge(leftArrow$, rightArrow$) .startWith({x: 100, y: 100}) .scan((acc, curr) => curr(acc)) .subscribe(result => this.position = result); }

Page 42: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

increment(obj, prop, value) { return Object.assign({}, obj, {[prop]: obj[prop] + value})}decrement(obj, prop, value) { return Object.assign({}, obj, {[prop]: obj[prop] - value})}ngOnInit() { const leftArrow$ = Observable.fromEvent(document, 'keydown') .filter(event => event.key === 'ArrowLeft') .mapTo(position => this.decrement(position, 'x', 10)); const rightArrow$ = Observable.fromEvent(document, 'keydown') .filter(event => event.key === 'ArrowRight') .mapTo(position => this.increment(position, 'x', 10)); Observable.merge(leftArrow$, rightArrow$) .startWith({x: 100, y: 100}) .scan((acc, curr) => curr(acc)) .subscribe(result => this.position = result); }

Page 43: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

increment(obj, prop, value) { return Object.assign({}, obj, {[prop]: obj[prop] + value})}decrement(obj, prop, value) { return Object.assign({}, obj, {[prop]: obj[prop] - value})}ngOnInit() { const leftArrow$ = Observable.fromEvent(document, 'keydown') .filter(event => event.key === 'ArrowLeft') .mapTo(position => this.decrement(position, 'x', 10)); const rightArrow$ = Observable.fromEvent(document, 'keydown') .filter(event => event.key === 'ArrowRight') .mapTo(position => this.increment(position, 'x', 10)); Observable.merge(leftArrow$, rightArrow$) .startWith({x: 100, y: 100}) .scan((acc, curr) => curr(acc)) .subscribe(result => this.position = result); }

Page 44: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

MAPPING TO FUNCTIONS

Page 45: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

How can we sequence a stream?

Page 46: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('ball') ball; position: any;ngOnInit() { const OFFSET = 50; const move$ = Observable.fromEvent(document, 'mousemove') .map(event => { return {x: event.pageX - OFFSET, y: event.pageY - OFFSET}; }); const down$ = Observable.fromEvent(this.ball.nativeElement, 'mousedown'); down$ .switchMap(event => move$) .startWith({ x: 100, y: 100}) .subscribe(result => this.position = result);}

Page 47: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('ball') ball;position: any;ngOnInit() { const OFFSET = 50; const move$ = Observable.fromEvent(document, 'mousemove') .map(event => { return {x: event.pageX - OFFSET, y: event.pageY - OFFSET}; }); const down$ = Observable.fromEvent(this.ball.nativeElement, 'mousedown'); down$ .switchMap(event => move$) .startWith({ x: 100, y: 100}) .subscribe(result => this.position = result); }

Page 48: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('ball') ball;position: any;ngOnInit() { const OFFSET = 50; const move$ = Observable.fromEvent(document, 'mousemove') .map(event => { return {x: event.pageX - OFFSET, y: event.pageY - OFFSET}; }); const down$ = Observable.fromEvent(this.ball.nativeElement, 'mousedown'); down$ .switchMap(event => move$) .startWith({ x: 100, y: 100}) .subscribe(result => this.position = result);}

Page 49: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('ball') ball;position: any;ngOnInit() { const OFFSET = 50; const move$ = Observable.fromEvent(document, 'mousemove') .map(event => { return {x: event.pageX - OFFSET, y: event.pageY - OFFSET}; }); const down$ = Observable.fromEvent(this.ball.nativeElement, 'mousedown'); down$ .switchMap(event => move$) .startWith({ x: 100, y: 100}) .subscribe(result => this.position = result);}

Page 50: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('ball') ball;position: any;ngOnInit() { const OFFSET = 50; const move$ = Observable.fromEvent(document, 'mousemove') .map(event => { return {x: event.pageX - OFFSET, y: event.pageY - OFFSET}; }); const down$ = Observable.fromEvent(this.ball.nativeElement, 'mousedown'); const up$ = Observable.fromEvent(document, 'mouseup'); down$ .switchMap(event => move$.takeUntil(up$)) .startWith({ x: 100, y: 100}) .subscribe(result => this.position = result); }

Page 51: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

TRIGGERS

Page 52: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

What effect does the origin of the stream have on the output?

Page 53: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

<div class="container"> <app-line *ngFor="let line of lines" [line]="line"> </app-line></div>

Page 54: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

<svg> <line [attr.x1]="line.x1" [attr.y1]="line.y1" [attr.x2]="line.x2" [attr.y2]="line.y2" style="stroke:rgb(255,0,0);stroke-width:2"/> </svg>

Page 55: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

lines: any[] = []; ngOnInit() { Observable.fromEvent(document, 'click') .map(event => { return {x: event.pageX, y: event.pageY}; }) .pairwise(2) .map(positions => { const p1 = positions[0]; const p2 = positions[1]; return { x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y }; }) .subscribe(line => this.lines = [...this.lines, line]);}

Page 56: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

STREAM ORIGINS

Page 57: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

lines: any[] = []; ngOnInit() { Observable.fromEvent(document, 'mousemove') .map(event => { return {x: event.pageX, y: event.pageY}; }) .pairwise(2) .map(position => { const p1 = positions[0]; const p2 = positions[1]; return { x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y }; }) .subscribe(line => this.lines = [...this.lines, line]);}

Page 58: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

STREAM ORIGINS

Page 59: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

What are some fun things we can do with a stream?

Page 60: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@ViewChild('ball') ball;ngOnInit() { const OFFSET = 50; Observable.fromEvent(document, 'click') .map(event => { return {x: event.clientX - OFFSET, y: event.clientY - OFFSET} }) .subscribe(props => TweenMax.to(this.ball.nativeElement, 1, props))}

Page 61: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

SIMPLE ANIMATION

Page 62: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

What are some MOAR fun things we can do with a stream?

Page 63: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

circles: any[] = [];ngOnInit() { const OFFSET = 25; Observable.fromEvent(document, 'mousemove') .map(event => { return { x: event.clientX - OFFSET, y: event.clientY - OFFSET} }) .subscribe(circle => this.circles = [ ...this.circles, circle])}

Page 64: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

<div class="container"> <app-circle *ngFor="let circle of circles" [style.left]="circle.x + 'px'" [style.top]="circle.y + 'px'"> </app-circle></div>

Page 65: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

export class CircleComponent implements OnInit { @ViewChild('circle') circle; ngOnInit() { TweenMax.to(this.circle.nativeElement, 2, {alpha: 0, width: 0, height: 0}); }}

Page 66: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

ANIMATION

Page 67: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

The Realtime Observable Stream

Page 68: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Start with a realtime database

Page 69: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

You called?

Page 70: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

import { AngularFireModule } from 'angularfire2'; export const firebaseConfig = { apiKey: 'PETERBACONDARWINISABEASTINSHEEPSCLOTHING', authDomain: 'rxjsbeastmode.firebaseapp.com', databaseURL: 'https://rxjsbeastmode.firebaseio.com', storageBucket: ''};@NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AngularFireModule.initializeApp(firebaseConfig), ], bootstrap: [AppComponent]})export class AppModule {}

Page 71: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

import { AngularFireModule } from 'angularfire2'; export const firebaseConfig = { apiKey: 'PETERBACONDARWINISABEASTINSHEEPSCLOTHING', authDomain: 'rxjsbeastmode.firebaseapp.com', databaseURL: 'https://rxjsbeastmode.firebaseio.com', storageBucket: ''};@NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AngularFireModule.initializeApp(firebaseConfig), ], bootstrap: [AppComponent]})export class AppModule {}

Page 72: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Consume the realtime stream

Page 73: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

const remote$ = this.af.database.object('clicker/');remote$ .subscribe(result => this.count = result.ticker);

Page 74: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Update the realtime stream

Page 75: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

const remote$ = this.af.database.object('clicker/');Observable.fromEvent(this.getNativeElement(this.btn), 'click') .startWith({ticker: 0}) .scan((acc, curr) => { return { ticker: acc.ticker + 1 }; }) .subscribe(event => remote$.update(event));

Page 76: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

const remote$ = this.af.database.object('clicker/');

// Outgoing Observable.fromEvent(this.getNativeElement(this.btn), 'click') .startWith({ticker: 0}) .scan((acc, curr) => { return { ticker: acc.ticker + 1 }; }) .subscribe(event => remote$.update(event));

// Incoming remote$ .subscribe(result => this.message = result.message);

Page 77: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

const remote$ = this.af.database.object('clicker/');

// Outgoing ——> Observable.fromEvent(this.getNativeElement(this.btn), 'click') .startWith({ticker: 0}) .scan((acc, curr) => { return { ticker: acc.ticker + 1 }; }) .subscribe(event => remote$.update(event));

// <—— Incoming remote$ .subscribe(result => this.message = result.message);

Page 78: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

BEAST MODE TIME!

Page 79: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME COUNTER

Page 80: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME SLIDESHOW

Page 81: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME LOCATION

Page 82: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME MAP

Page 83: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME ANNOTATIONS

Page 84: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME GAME

Page 85: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

BUSINESS MODE TIME!

Page 86: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

REALTIME SLIDER

Page 87: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

But observables are hard!!!

Page 88: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

I YOU!

Page 89: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

@simpulton

Page 90: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

https://egghead.io/courses/step-by-step-async-javascript-with-rxjs

Page 91: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

https://egghead.io/courses/introduction-to-reactive-programming

Page 92: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase
Page 93: Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase

Thanks!