SlideShare uma empresa Scribd logo
1 de 93
Baixar para ler offline
Go Beast Mode
with Realtime
Reactive Interfaces
in Angular and Firebase
State management
Controlling flow
Code volume
Enter Observables
return this.http.get(this.URLS.FETCH)

.map(res => res.json())

.toPromise();
Problem solved!
Observables give us a powerful way to encapsulate,
transport and transform data from user interactions
to create powerful and immersive experiences.
Encapsulate
Transport
Transform
Encapsulate
Transport
Transform
Encapsulate
Transport
Transform
Iterator Pattern Observer Pattern
State Communication
Communicate
state over time
Observable stream
Values over time
SINGLE MULTIPLE
SYNCHRONOUS Function Enumerable
ASYNCHRONOUS Promise Observable
Value consumption
SINGLE MULTIPLE
PULL Function Enumerable
PUSH Promise Observable
But
observables
are hard!!!
The
Observable
Stream
input output
output input
The
Basic
Sequence
final input
initial output
magic
subscribe
event
operators
@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;

}
@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
@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
@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
@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
BASIC SEQUENCE
How do we
preserve state
in a stream?
<button #right>Right</button>

<div class="container">

<div #ball class="ball"

[style.left]="position.x + 'px'"

[style.top]="position.y + 'px'">

</div>

</div>
@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);

}
@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);

}
@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);

}
@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);

}
MAINTAINING STATE
What if we have
more than one stream?
@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);

}
@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);

}
MERGING STREAMS
What can we
put in a stream?
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);

}
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);

}
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);

}
MAPPING TO FUNCTIONS
How can we
sequence a stream?
@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);

}
@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);

}
@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);

}
@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);

}
@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);

}
TRIGGERS
What effect does the
origin of the stream
have on the output?
<div class="container">

<app-line

*ngFor="let line of lines" [line]="line">

</app-line>

</div>
<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>
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]);

}
STREAM ORIGINS
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]);

}
STREAM ORIGINS
What are some fun
things we can do with
a stream?
@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))

}
SIMPLE ANIMATION
What are some MOAR
fun things we can do
with a stream?
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])

}
<div class="container">

<app-circle

*ngFor="let circle of circles"

[style.left]="circle.x + 'px'"

[style.top]="circle.y + 'px'">

</app-circle>

</div>
export class CircleComponent implements OnInit {

@ViewChild('circle') circle;



ngOnInit() {

TweenMax.to(this.circle.nativeElement, 2, 

{alpha: 0, width: 0, height: 0});

}

}
ANIMATION
The
Realtime
Observable
Stream
Start with a
realtime database
You
called?
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 {}
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 {}
Consume the
realtime stream
const remote$ = this.af.database.object('clicker/');



remote$

.subscribe(result => this.count = result.ticker);
Update the
realtime stream
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));
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);
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);
BEAST MODE TIME!
REALTIME COUNTER
REALTIME SLIDESHOW
REALTIME LOCATION
REALTIME MAP
REALTIME ANNOTATIONS
REALTIME GAME
BUSINESS MODE TIME!
REALTIME SLIDER
But
observables
are hard!!!
I YOU!
@simpulton
https://egghead.io/courses/step-by-step-async-javascript-with-rxjs
https://egghead.io/courses/introduction-to-reactive-programming
Thanks!

Mais conteúdo relacionado

Mais procurados

rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
Alexander Mostovenko
 
Bindings: the zen of montage
Bindings: the zen of montageBindings: the zen of montage
Bindings: the zen of montage
Kris Kowal
 

Mais procurados (20)

Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
 
google play service 7.8 & new tech in M
google play service 7.8 & new tech in M google play service 7.8 & new tech in M
google play service 7.8 & new tech in M
 
The Ring programming language version 1.8 book - Part 65 of 202
The Ring programming language version 1.8 book - Part 65 of 202The Ring programming language version 1.8 book - Part 65 of 202
The Ring programming language version 1.8 book - Part 65 of 202
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Higher-Order Components — Ilya Gelman
Higher-Order Components — Ilya GelmanHigher-Order Components — Ilya Gelman
Higher-Order Components — Ilya Gelman
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creators
 
Java awt
Java awtJava awt
Java awt
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
 
Clojure functions examples
Clojure functions examplesClojure functions examples
Clojure functions examples
 
AngularJS, More Than Directives !
AngularJS, More Than Directives !AngularJS, More Than Directives !
AngularJS, More Than Directives !
 
The Ring programming language version 1.6 book - Part 68 of 189
The Ring programming language version 1.6 book - Part 68 of 189The Ring programming language version 1.6 book - Part 68 of 189
The Ring programming language version 1.6 book - Part 68 of 189
 
Using Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side EffectsUsing Redux-Saga for Handling Side Effects
Using Redux-Saga for Handling Side Effects
 
Tweaking the interactive grid
Tweaking the interactive gridTweaking the interactive grid
Tweaking the interactive grid
 
Actividad #7 codigo detección de errores (yango colmenares)
Actividad #7 codigo detección de errores (yango colmenares)Actividad #7 codigo detección de errores (yango colmenares)
Actividad #7 codigo detección de errores (yango colmenares)
 
The Ring programming language version 1.5.1 book - Part 62 of 180
The Ring programming language version 1.5.1 book - Part 62 of 180The Ring programming language version 1.5.1 book - Part 62 of 180
The Ring programming language version 1.5.1 book - Part 62 of 180
 
Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018
 
Bindings: the zen of montage
Bindings: the zen of montageBindings: the zen of montage
Bindings: the zen of montage
 
Model View Intent on Android
Model View Intent on AndroidModel View Intent on Android
Model View Intent on Android
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 

Destaque

Destaque (13)

Get that Corner Office with Angular 2 and Electron
Get that Corner Office with Angular 2 and ElectronGet that Corner Office with Angular 2 and Electron
Get that Corner Office with Angular 2 and Electron
 
Embrace the Angular 2 Ethos in Angular 1.x
Embrace the Angular 2 Ethos in Angular 1.xEmbrace the Angular 2 Ethos in Angular 1.x
Embrace the Angular 2 Ethos in Angular 1.x
 
Turn Your Designers Into Death Stars with Angular
Turn Your Designers Into Death Stars with AngularTurn Your Designers Into Death Stars with Angular
Turn Your Designers Into Death Stars with Angular
 
The REAL Angular Keynote
The REAL Angular KeynoteThe REAL Angular Keynote
The REAL Angular Keynote
 
Badges? We don't need no stinkin' badges!
Badges? We don't need no stinkin' badges!Badges? We don't need no stinkin' badges!
Badges? We don't need no stinkin' badges!
 
AngularJS Directives - DSL for your HTML
AngularJS Directives - DSL for your HTMLAngularJS Directives - DSL for your HTML
AngularJS Directives - DSL for your HTML
 
ngEurope 2014: Become a Realtime Cage Dragon with Firebase and AngularJS
ngEurope 2014: Become a Realtime Cage Dragon with Firebase and AngularJSngEurope 2014: Become a Realtime Cage Dragon with Firebase and AngularJS
ngEurope 2014: Become a Realtime Cage Dragon with Firebase and AngularJS
 
ngAnimate crash course
ngAnimate crash coursengAnimate crash course
ngAnimate crash course
 
Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
 
Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)
 
Ionic Crash Course! Hack-a-ton SF
Ionic Crash Course! Hack-a-ton SFIonic Crash Course! Hack-a-ton SF
Ionic Crash Course! Hack-a-ton SF
 
Summer internship report | repairwale.com mobile application design and devel...
Summer internship report | repairwale.com mobile application design and devel...Summer internship report | repairwale.com mobile application design and devel...
Summer internship report | repairwale.com mobile application design and devel...
 

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

Create a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfCreate a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdf
arihantmobileselepun
 
Modern JavaScript Engine Performance
Modern JavaScript Engine PerformanceModern JavaScript Engine Performance
Modern JavaScript Engine Performance
Catalin Dumitru
 
package chapter15;import javafx.application.Application;import j.pdf
package chapter15;import javafx.application.Application;import j.pdfpackage chapter15;import javafx.application.Application;import j.pdf
package chapter15;import javafx.application.Application;import j.pdf
KARTIKINDIA
 
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxsrcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
whitneyleman54422
 

Semelhante a Go Beast Mode with Realtime Reactive Interfaces in Angular 2 and Firebase (20)

You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
 
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術
 
KODE JS POKENNNNN
KODE JS POKENNNNNKODE JS POKENNNNN
KODE JS POKENNNNN
 
Cyclejs introduction
Cyclejs introductionCyclejs introduction
Cyclejs introduction
 
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
 
Let it Flow - Introduction to Functional Reactive Programming
Let it Flow - Introduction to Functional Reactive ProgrammingLet it Flow - Introduction to Functional Reactive Programming
Let it Flow - Introduction to Functional Reactive Programming
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
bacon.js
bacon.jsbacon.js
bacon.js
 
Create a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfCreate a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdf
 
Modern JavaScript Engine Performance
Modern JavaScript Engine PerformanceModern JavaScript Engine Performance
Modern JavaScript Engine Performance
 
Effector: we need to go deeper
Effector: we need to go deeperEffector: we need to go deeper
Effector: we need to go deeper
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 
package chapter15;import javafx.application.Application;import j.pdf
package chapter15;import javafx.application.Application;import j.pdfpackage chapter15;import javafx.application.Application;import j.pdf
package chapter15;import javafx.application.Application;import j.pdf
 
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.
 
React 101
React 101React 101
React 101
 
React.js: Beyond the Browser
React.js: Beyond the BrowserReact.js: Beyond the Browser
React.js: Beyond the Browser
 
Ruby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery SpaghettiRuby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery Spaghetti
 
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxsrcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
 
04 Advanced Javascript
04 Advanced Javascript04 Advanced Javascript
04 Advanced Javascript
 
Creating an Uber Clone - Part XVIII - Transcript.pdf
Creating an Uber Clone - Part XVIII - Transcript.pdfCreating an Uber Clone - Part XVIII - Transcript.pdf
Creating an Uber Clone - Part XVIII - Transcript.pdf
 

Último

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Último (20)

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 

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

  • 1. Go Beast Mode with Realtime Reactive Interfaces in Angular and Firebase
  • 6. return this.http.get(this.URLS.FETCH)
 .map(res => res.json())
 .toPromise(); Problem solved!
  • 7. Observables give us a powerful way to encapsulate, transport and transform data from user interactions to create powerful and immersive experiences.
  • 11. Iterator Pattern Observer Pattern State Communication
  • 14. Values over time SINGLE MULTIPLE SYNCHRONOUS Function Enumerable ASYNCHRONOUS Promise Observable
  • 15. Value consumption SINGLE MULTIPLE PULL Function Enumerable PUSH Promise Observable
  • 23. @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;
 }
  • 24. @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
  • 25. @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
  • 26. @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
  • 27. @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
  • 29. How do we preserve state in a stream?
  • 30. <button #right>Right</button>
 <div class="container">
 <div #ball class="ball"
 [style.left]="position.x + 'px'"
 [style.top]="position.y + 'px'">
 </div>
 </div>
  • 31. @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);
 }
  • 32. @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);
 }
  • 33. @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);
 }
  • 34. @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);
 }
  • 36. What if we have more than one stream?
  • 37. @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);
 }
  • 38. @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);
 }
  • 40. What can we put in a stream?
  • 41. 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);
 }
  • 42. 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);
 }
  • 43. 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);
 }
  • 45. How can we sequence a stream?
  • 46. @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);
 }
  • 47. @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);
 }
  • 48. @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);
 }
  • 49. @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);
 }
  • 50. @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);
 }
  • 52. What effect does the origin of the stream have on the output?
  • 53. <div class="container">
 <app-line
 *ngFor="let line of lines" [line]="line">
 </app-line>
 </div>
  • 54. <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>
  • 55. 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]);
 }
  • 57. 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]);
 }
  • 59. What are some fun things we can do with a stream?
  • 60. @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))
 }
  • 62. What are some MOAR fun things we can do with a stream?
  • 63. 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])
 }
  • 64. <div class="container">
 <app-circle
 *ngFor="let circle of circles"
 [style.left]="circle.x + 'px'"
 [style.top]="circle.y + 'px'">
 </app-circle>
 </div>
  • 65. export class CircleComponent implements OnInit {
 @ViewChild('circle') circle;
 
 ngOnInit() {
 TweenMax.to(this.circle.nativeElement, 2, 
 {alpha: 0, width: 0, height: 0});
 }
 }
  • 70. 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 {}
  • 71. 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 {}
  • 73. const remote$ = this.af.database.object('clicker/');
 
 remote$
 .subscribe(result => this.count = result.ticker);
  • 75. 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));
  • 76. 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);
  • 77. 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);
  • 92.