SlideShare une entreprise Scribd logo
1  sur  93
Télécharger pour lire hors ligne
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!

Contenu connexe

Tendances

Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript名辰 洪
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga beginsDaniel Franz
 
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 Ted Liang
 
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 202Mahmoud Samir Fayed
 
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 es6Ignacio Martín
 
Higher-Order Components — Ilya Gelman
Higher-Order Components — Ilya GelmanHigher-Order Components — Ilya Gelman
Higher-Order Components — Ilya Gelman500Tech
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creatorsGeorge Bukhanov
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simplerAlexander Mostovenko
 
AngularJS, More Than Directives !
AngularJS, More Than Directives !AngularJS, More Than Directives !
AngularJS, More Than Directives !Gaurav Behere
 
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 189Mahmoud Samir Fayed
 
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 EffectsGlobalLogic Ukraine
 
Tweaking the interactive grid
Tweaking the interactive gridTweaking the interactive grid
Tweaking the interactive gridRoel Hartman
 
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)Yango Alexander 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 180Mahmoud Samir Fayed
 
Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018Reactive programming with RxJS - ByteConf 2018
Reactive programming with RxJS - ByteConf 2018Tracy Lee
 
Bindings: the zen of montage
Bindings: the zen of montageBindings: the zen of montage
Bindings: the zen of montageKris Kowal
 
Model View Intent on Android
Model View Intent on AndroidModel View Intent on Android
Model View Intent on AndroidCody Engel
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 

Tendances (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
 

En vedette

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 ElectronLukas Ruebbelke
 
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.xLukas Ruebbelke
 
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 AngularLukas Ruebbelke
 
The REAL Angular Keynote
The REAL Angular KeynoteThe REAL Angular Keynote
The REAL Angular KeynoteLukas Ruebbelke
 
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!Lukas Ruebbelke
 
AngularJS Directives - DSL for your HTML
AngularJS Directives - DSL for your HTMLAngularJS Directives - DSL for your HTML
AngularJS Directives - DSL for your HTMLLukas Ruebbelke
 
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 AngularJSLukas Ruebbelke
 
Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015Impress Your Friends with EcmaScript 2015
Impress Your Friends with EcmaScript 2015Lukas Ruebbelke
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptViliam Elischer
 
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)Eyal Vardi
 
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 SFLukas Ruebbelke
 
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...Rajath Thomson
 

En vedette (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...
 

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

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 POKENNNNNPipo Atem
 
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 - делаем асинхр...GeeksLab Odessa
 
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 ProgrammingArtur Skowroński
 
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.pdfarihantmobileselepun
 
Modern JavaScript Engine Performance
Modern JavaScript Engine PerformanceModern JavaScript Engine Performance
Modern JavaScript Engine PerformanceCatalin Dumitru
 
Effector: we need to go deeper
Effector: we need to go deeperEffector: we need to go deeper
Effector: we need to go deeperVictor Didenko
 
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 2016Ben Lesh
 
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.pdfKARTIKINDIA
 
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.Astrails
 
React.js: Beyond the Browser
React.js: Beyond the BrowserReact.js: Beyond the Browser
React.js: Beyond the Browsergarbles
 
Ruby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery SpaghettiRuby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery SpaghettiForrest Chang
 
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxsrcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxwhitneyleman54422
 
04 Advanced Javascript
04 Advanced Javascript04 Advanced Javascript
04 Advanced Javascriptcrgwbr
 
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.pdfShaiAlmog1
 

Similaire à 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
 

Dernier

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
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 FresherRemote DBA Services
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 

Dernier (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
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
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 

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.