KEMBAR78
Using redux and angular 2 with meteor | PDF
Using Redux and
Angular 2 with Meteor
Ken Ono
Principal and CTO
Fabrica Technology
September 21, 2016
Introductions
• Host Facility Introduction and Thanks
• Attendee Intros
– Recruiters or Recruiting?
– Potentially available for hires
– Individual Intros (First Name, Current Employer, Tech Interests, Experience with Meteor,
Angular 2 or Redux)
• About Ken
– Current
• Principal and CTO of Fabrica Technology (CTO for Hire)
• VP Analytics @ TBA
• CTO @ Aluvion Law
– Formerly
• CTO of Angoss Software (data mining)
• VP Analytics and Innovation at NexJ Systems (enterprise CRM and consumer health and wellness)
• CTO of Myant (Smart Garments).
– Blog at: www.fabrica.tech
Agenda
• Introductions
• Introduction to Angular 2
• Introduction to Redux
• Overview of an Approach for Meteor, Redux, Angular
• Let’s Look at Code
• Questions / deep dives at the end
Angular 2 - Important Prerequisites
• ES6
• TypeScript
• RxJS
ES6
– http://es6-features.org/
– Lambda / Arrow Function
Syntax
• function(x){} same as (x)=>{}
• ()=>{1} same as ()=>{return 1}
• a=>{a*2};
– Classes (prototypical
inheritance)
– `` strings
– let / const (new scoping rules)
– Extended Parameters
• Defaults: (x, b=1)=>{}
• Rest: (x,y, …a )=>{} (a is an array of
remaining params)
• Spread: [1, …[2,3]] same as [1,2,3]
– Property Short Hand:
• {x} same as {x:x}
– Iterators & Generators
– Import/export Modules
TypeScript
– https://www.typescriptlang.org
– Superset of ES6
– Compiles to ES5 (or 6)
– Adds type checking, interfaces, generics and more
– Decorators
• annotating or modifying classes and class members
• experimental, but heavily used by Angular 2
• http://rangle.io/resources/demystifying-decorators-a-
new-feature-to-javascript/
export enum EDocumentChangeType {
NEW,
CHANGED,
REMOVED,
MOVED
}
export interface IDocumentChange<T> {
changeType:EDocumentChangeType,
newDocument?: T,
oldDocument?: T,
atIndex?:number,
before?:string
fromIndex?:number
}
…
export class MeteorCursorObservers {
static createCursorObserver<T>(ursor: Mongo.Cursor<any>): Observable<IDocumentChange<T>> {
return Observable.create(
(observer: Subscriber<IDocumentChange<T>>) => {
let handle: Meteor.LiveQueryHandle = cursor.observe({
…
Not your father’s JavaScript
RxJS
– http://reactivex.io/
– Create and subscribe to streams
– Observable
• Like Promise except next(), error(), complete()
– Library of operators make it like lodash/_, but for streams
• Streams are like arrays, except over time, instead of indexed in memory
– Declarative, not imperative
– Hot (mouse clicks/live play) vs Cold (server request/DVD)
– Will be part of JavaScript (currently stage one proposal)
let myObservable<MyType> = somthingThatGivesMeAnObservable();
let subscription:Subscription = myObservablle.subsribe(
(myData:MyType)=>{}, // Data pushed to you from Observable
()=>{}, // Error
()=>{} // Complete
);
subSrciption.unsubscribe();
…
myObservable.map( funciton (myData:MyType) {
return transformed(myData);
}). …
// Short hand:
myObservable.map( myData:MyType=> transformed(myData));
Key Angular 2 Features
• Components and Directives
– Hierarchical tree of components
– Properties in / Events out
– Templating, two-way binding and built
in directives
– Life Cycle Events
• Forms
• Services
– HTTP
– Router
• Pipes
• Dependency Injection
• Testing
• Animation
• Modules
• Web Workers
• Client options (Bootstrap, Angular Material,
Ionic (Native look and feel with Cordova),
NativeScript (Angular 2 & JS with iOS and Android
native components - No DOM), Angular Universal,
Electron (browser and Node bundle for desktop)
• CLI
• https://angular.io/docs/ts/latest/guide/cheatsheet.html
• http://rangle.io/resources/intro-to-angular-2-components/
Redux
• A central nervous system for events and actions to derive a clean, well-defined
application state.
• A New Way of Organizing Code that is simple to conceptualize:
– Actions (that have an action type and payload) are fired,
– A reducer computes a new state with pure functions given an action and current state,
– Middleware handles anything asynchronous (actions in, actions out)
UI Actions Reducer
StateStateStateState
Middle
ware
Putting Redux into practice is a mental adjustment
Yuri Takhteyev, CTO of Rangle, intro to Redux
https://www.youtube.com/watch?v=s9AC8KTcce8
Redux Module
• My approach to organizing Redux pieces
• Define a reducer, set of actions and async
handlers as a bundle
• Let’s look at a few modules that map to Meteor
features
– Organizing Actions
– Updating State
– Async and connecting to Meteor services
– Connecting to Angular Components
export abstract class ReduxModule<T> {
reducer:Reducer<T>;
epics:Epic[]=[]; // Stream based middleware
middlewares:any[]=[]; // Normal redux middleware
enhancers:any[]=[];
actions:Object;
abstract initialize():void;
}
…
Patterns
• Request, Manage, Respond, Listen – a Redux Pattern
– Kick off a request action
– Middleware reacts to the request and kicks off server call. (Promises and RxJS to
manage the asynchronous events.)
– Server returns data (a single response or many responses from a watch)
– Response action fired with data from server (or error condition)
– Your reducer updates the application state with the new data
– Presentation components wait for the information they need to arrive
• Write and Watch - a Meteor/Redux Pattern
– Write data to a Mongo Collection (via Collection.insert, Meteor.method)
– Observe changes
Meteor – Cursor.observe
• Mongo.Cursor#observe
– Watch a query. Receive callbacks as the result of Mongo query changes.
– Callbacks for
• Added(document) or
• Changed(newDocument, oldDocument) or
• Removed(oldDocument)
• http://docs.meteor.com/api/collections.html#Mongo-Cursor-observe
Wrapping a Meteor Cursor with an Observable
• Convert a reactive Meteor cursor to an
Observable:
fromMeteorCursor<T>(cursor: Mongo.Cursor<any>):
Observable<IDocumentChange<T>> {
return Observable.create((observer:
Subscriber<IDocumentChange<T>>) => {
let handle: Meteor.LiveQueryHandle = cursor.observe({
added: (doc: T) => {
observer.next({
changeType: EDocumentChangeType.NEW,
newDocument: doc
});
},
changed: (nDoc: T, oDoc: T) => {
observer.next({
changeType: EDocumentChangeType.CHANGED,
newDocument: nDoc,
oldDocument: oDoc
});
},
removed: (doc: T) => {
observer.next({
changeType: EDocumentChangeType.REMOVED,
• Then observe the cursor:
static createUserObserver(userId:string):Observable<IDocumentChange<User>>
{
return MeteorCursorObservers. fromMeteorCursor<User>(
Meteor.users.find({_id: userId})
);
}
.createUserObserver(LoginService.userId()).map(
(change:IDocumentChange<User>)=>{
let loginState:ILoginState = store.getState().loginReducer;
if (loginState && loginState.neverLoggedIn) {
// Never logged in, yet the current user is populated, must be
automatic login
return LoginActions.loginSuccessFactory(
change.newDocument,
change.newDocument._id, true);
} else {
return LoginActions.changeFactory(change);
}
})
Other Important Packages
• Immutable.js - new state generation
– Provides immutable maps and arrays (and more)
– https://facebook.github.io/immutable-js/
– https://www.youtube.com/watch?v=I7IdS-PbEgI
• NgRedux - Angular bindings for Redux
– @select decorators, injectable store and dispatcher
– https://github.com/angular-redux/ng-redux
– https://www.youtube.com/watch?v=s4xr2avwv3s
• Redux-Observable - RxJS middleware
– Use RxJS operators (.filter, .map, .flatMap) for
async operations
– https://github.com/redux-observable/redux-
observable
var Immutable = require('immutable');
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50
@Component(…)
class App {
@select() count$: Observable<number>;
constructor(private ngr: NgRedux<IAppState>) {}
onClick() { this.ngr.dispatch({ type: INC); }
}
const pingEpic = action$ =>
action$.filter(action => action.type === 'PING')
.delay(1000) // wait 1000ms
.mapTo({ type: 'PONG' });
// later... dispatch({ type: 'PING' });
Demo App
• For Real Cards (attempts to mimic actual card, game engine does not know
rules)
• Source Code: https://github.com/kokokenada/for-real-cards
• Hosted at: http://for-real-cards.scalingo.io/
• Mobile app: Search for ”for real cards Fabrica”
Conclusion
• Impact to Code
– Reduced boiler plate (compared to using RxJS for actions)
– Consolidated logic, less spaghetti code
– Clean separation of presentation and data acquisition
– Way, way easier to debug
– Easier to develop rich functionality and reason about state and events
– State is solidly understood
– Less deep nesting / micro-management of async calls
– Simple undo
• Challenges
– New way of thinking an organizing code
– Lots of prerequisites to learn
– Getting immutability right (for complex structures) takes practice
– Tooling is catching up
It’s hard work, but it will pay off

Using redux and angular 2 with meteor

  • 1.
    Using Redux and Angular2 with Meteor Ken Ono Principal and CTO Fabrica Technology September 21, 2016
  • 2.
    Introductions • Host FacilityIntroduction and Thanks • Attendee Intros – Recruiters or Recruiting? – Potentially available for hires – Individual Intros (First Name, Current Employer, Tech Interests, Experience with Meteor, Angular 2 or Redux) • About Ken – Current • Principal and CTO of Fabrica Technology (CTO for Hire) • VP Analytics @ TBA • CTO @ Aluvion Law – Formerly • CTO of Angoss Software (data mining) • VP Analytics and Innovation at NexJ Systems (enterprise CRM and consumer health and wellness) • CTO of Myant (Smart Garments). – Blog at: www.fabrica.tech
  • 3.
    Agenda • Introductions • Introductionto Angular 2 • Introduction to Redux • Overview of an Approach for Meteor, Redux, Angular • Let’s Look at Code • Questions / deep dives at the end
  • 4.
    Angular 2 -Important Prerequisites • ES6 • TypeScript • RxJS
  • 5.
    ES6 – http://es6-features.org/ – Lambda/ Arrow Function Syntax • function(x){} same as (x)=>{} • ()=>{1} same as ()=>{return 1} • a=>{a*2}; – Classes (prototypical inheritance) – `` strings – let / const (new scoping rules) – Extended Parameters • Defaults: (x, b=1)=>{} • Rest: (x,y, …a )=>{} (a is an array of remaining params) • Spread: [1, …[2,3]] same as [1,2,3] – Property Short Hand: • {x} same as {x:x} – Iterators & Generators – Import/export Modules
  • 6.
    TypeScript – https://www.typescriptlang.org – Supersetof ES6 – Compiles to ES5 (or 6) – Adds type checking, interfaces, generics and more – Decorators • annotating or modifying classes and class members • experimental, but heavily used by Angular 2 • http://rangle.io/resources/demystifying-decorators-a- new-feature-to-javascript/ export enum EDocumentChangeType { NEW, CHANGED, REMOVED, MOVED } export interface IDocumentChange<T> { changeType:EDocumentChangeType, newDocument?: T, oldDocument?: T, atIndex?:number, before?:string fromIndex?:number } … export class MeteorCursorObservers { static createCursorObserver<T>(ursor: Mongo.Cursor<any>): Observable<IDocumentChange<T>> { return Observable.create( (observer: Subscriber<IDocumentChange<T>>) => { let handle: Meteor.LiveQueryHandle = cursor.observe({ … Not your father’s JavaScript
  • 7.
    RxJS – http://reactivex.io/ – Createand subscribe to streams – Observable • Like Promise except next(), error(), complete() – Library of operators make it like lodash/_, but for streams • Streams are like arrays, except over time, instead of indexed in memory – Declarative, not imperative – Hot (mouse clicks/live play) vs Cold (server request/DVD) – Will be part of JavaScript (currently stage one proposal) let myObservable<MyType> = somthingThatGivesMeAnObservable(); let subscription:Subscription = myObservablle.subsribe( (myData:MyType)=>{}, // Data pushed to you from Observable ()=>{}, // Error ()=>{} // Complete ); subSrciption.unsubscribe(); … myObservable.map( funciton (myData:MyType) { return transformed(myData); }). … // Short hand: myObservable.map( myData:MyType=> transformed(myData));
  • 8.
    Key Angular 2Features • Components and Directives – Hierarchical tree of components – Properties in / Events out – Templating, two-way binding and built in directives – Life Cycle Events • Forms • Services – HTTP – Router • Pipes • Dependency Injection • Testing • Animation • Modules • Web Workers • Client options (Bootstrap, Angular Material, Ionic (Native look and feel with Cordova), NativeScript (Angular 2 & JS with iOS and Android native components - No DOM), Angular Universal, Electron (browser and Node bundle for desktop) • CLI • https://angular.io/docs/ts/latest/guide/cheatsheet.html • http://rangle.io/resources/intro-to-angular-2-components/
  • 9.
    Redux • A centralnervous system for events and actions to derive a clean, well-defined application state. • A New Way of Organizing Code that is simple to conceptualize: – Actions (that have an action type and payload) are fired, – A reducer computes a new state with pure functions given an action and current state, – Middleware handles anything asynchronous (actions in, actions out) UI Actions Reducer StateStateStateState Middle ware Putting Redux into practice is a mental adjustment Yuri Takhteyev, CTO of Rangle, intro to Redux https://www.youtube.com/watch?v=s9AC8KTcce8
  • 10.
    Redux Module • Myapproach to organizing Redux pieces • Define a reducer, set of actions and async handlers as a bundle • Let’s look at a few modules that map to Meteor features – Organizing Actions – Updating State – Async and connecting to Meteor services – Connecting to Angular Components export abstract class ReduxModule<T> { reducer:Reducer<T>; epics:Epic[]=[]; // Stream based middleware middlewares:any[]=[]; // Normal redux middleware enhancers:any[]=[]; actions:Object; abstract initialize():void; } …
  • 11.
    Patterns • Request, Manage,Respond, Listen – a Redux Pattern – Kick off a request action – Middleware reacts to the request and kicks off server call. (Promises and RxJS to manage the asynchronous events.) – Server returns data (a single response or many responses from a watch) – Response action fired with data from server (or error condition) – Your reducer updates the application state with the new data – Presentation components wait for the information they need to arrive • Write and Watch - a Meteor/Redux Pattern – Write data to a Mongo Collection (via Collection.insert, Meteor.method) – Observe changes
  • 12.
    Meteor – Cursor.observe •Mongo.Cursor#observe – Watch a query. Receive callbacks as the result of Mongo query changes. – Callbacks for • Added(document) or • Changed(newDocument, oldDocument) or • Removed(oldDocument) • http://docs.meteor.com/api/collections.html#Mongo-Cursor-observe
  • 13.
    Wrapping a MeteorCursor with an Observable • Convert a reactive Meteor cursor to an Observable: fromMeteorCursor<T>(cursor: Mongo.Cursor<any>): Observable<IDocumentChange<T>> { return Observable.create((observer: Subscriber<IDocumentChange<T>>) => { let handle: Meteor.LiveQueryHandle = cursor.observe({ added: (doc: T) => { observer.next({ changeType: EDocumentChangeType.NEW, newDocument: doc }); }, changed: (nDoc: T, oDoc: T) => { observer.next({ changeType: EDocumentChangeType.CHANGED, newDocument: nDoc, oldDocument: oDoc }); }, removed: (doc: T) => { observer.next({ changeType: EDocumentChangeType.REMOVED, • Then observe the cursor: static createUserObserver(userId:string):Observable<IDocumentChange<User>> { return MeteorCursorObservers. fromMeteorCursor<User>( Meteor.users.find({_id: userId}) ); } .createUserObserver(LoginService.userId()).map( (change:IDocumentChange<User>)=>{ let loginState:ILoginState = store.getState().loginReducer; if (loginState && loginState.neverLoggedIn) { // Never logged in, yet the current user is populated, must be automatic login return LoginActions.loginSuccessFactory( change.newDocument, change.newDocument._id, true); } else { return LoginActions.changeFactory(change); } })
  • 14.
    Other Important Packages •Immutable.js - new state generation – Provides immutable maps and arrays (and more) – https://facebook.github.io/immutable-js/ – https://www.youtube.com/watch?v=I7IdS-PbEgI • NgRedux - Angular bindings for Redux – @select decorators, injectable store and dispatcher – https://github.com/angular-redux/ng-redux – https://www.youtube.com/watch?v=s4xr2avwv3s • Redux-Observable - RxJS middleware – Use RxJS operators (.filter, .map, .flatMap) for async operations – https://github.com/redux-observable/redux- observable var Immutable = require('immutable'); var map1 = Immutable.Map({a:1, b:2, c:3}); var map2 = map1.set('b', 50); map1.get('b'); // 2 map2.get('b'); // 50 @Component(…) class App { @select() count$: Observable<number>; constructor(private ngr: NgRedux<IAppState>) {} onClick() { this.ngr.dispatch({ type: INC); } } const pingEpic = action$ => action$.filter(action => action.type === 'PING') .delay(1000) // wait 1000ms .mapTo({ type: 'PONG' }); // later... dispatch({ type: 'PING' });
  • 15.
    Demo App • ForReal Cards (attempts to mimic actual card, game engine does not know rules) • Source Code: https://github.com/kokokenada/for-real-cards • Hosted at: http://for-real-cards.scalingo.io/ • Mobile app: Search for ”for real cards Fabrica”
  • 16.
    Conclusion • Impact toCode – Reduced boiler plate (compared to using RxJS for actions) – Consolidated logic, less spaghetti code – Clean separation of presentation and data acquisition – Way, way easier to debug – Easier to develop rich functionality and reason about state and events – State is solidly understood – Less deep nesting / micro-management of async calls – Simple undo • Challenges – New way of thinking an organizing code – Lots of prerequisites to learn – Getting immutability right (for complex structures) takes practice – Tooling is catching up It’s hard work, but it will pay off