Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Angular2 + rxjs

1,832 views

Published on

Angular 2 presentation components, routing, bootstrap and how to use with rxjs

Published in: Technology
  • ♣♣ 10 Easy Ways to Improve Your Performance in Bed... ●●● https://tinyurl.com/rockhardxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Angular2 + rxjs

  1. 1. Angular 2 with rxjs chris noring Frontend Developer OVO Energy, London Google Developer Expert
  2. 2. Who am I @chris_noring
  3. 3. Why angular 2
  4. 4. Backed by google It’s released !! It’s fast It uses typescript It uses components compile time type checking good when teams and codebase grows Fewer concepts to learn than angular 1 Mobile first Designed to be memory efficient and less CPU cycles Faster than React, less fast than Vue.js Tooling like angular-cli 1 2 3 4 5 6 7
  5. 5. Bootstrapping ng-1 index.html app.js ng-app =“app” angular.module(‘app’, [ dep1, dep2, dep3 ]) .controller() .service() .factory() .filter() 1 2
  6. 6. Bootstrapping ng 2 main.ts app.module.ts platform.bootstrapModule(AppModule); app.component component1 component n.. module1 module1 1 2 define dependant modules define components our module consist of define services bootstrap app
  7. 7. Filter Constant/ Value @Pipe Service, factory, provider vanilla javascript ng1 ng2 Less concepts filter is faster, more js vanilla more performant .constant .value .factory, .service, .provider
  8. 8. Module Router ngModule Much more powerful ng1 ng2 Less concepts modules + better router lazy loading built for > 100k routes better separation, its not all global like ng1
  9. 9. Controller Directive element @Component @Directive . Directive Attrib Less concepts . Directive Structural
  10. 10. Bindings
  11. 11. Bindings - one way <div [attr] =“prop” > </div> export class SomeComponent{ prop:string; } {{ prop }} [ someAttribute ]
  12. 12. Event binding <div (click)=“method()”> export class SomeComponent{ method(){ // do something } } (event)=“method()”
  13. 13. Banana in a box, 2-way <input [(ngModel)]=“user.name”> export class SomeComponent{ user:User; } shorthand for class User{ name:string; } banana in a box [(ngModel)]=“dataProperty” <input [value]=“user.name" (input)=“user.name = $event.target.value">
  14. 14. Directives
  15. 15. 3 directive types Structural Attribute Component @Directive({ }) export class SomeClass{ } @Component({}) export class SomeComponent{ }
  16. 16. Structural directives changes the DOM layout by adding and removing DOM elements <div *ngIf=“condition”> some text.. <div/> add or remove from DOM tree <div *ngFor=“let item of items”> {{ item.prop }} </div> <div [ngSwitch]="status"> <template [ngSwitchCase]=“'beginner'">Young padawan</template> <template [ngSwitchCase]="'expert'">Jedi</template> <template ngSwitchDefault>Unknown</template> </div> create one tow for each items select one matching case
  17. 17. Attribute directive changes the appearance or behavior of a DOM element import { Directive, ElementRef, Input, Renderer } from '@angular/core'; @Directive({ selector: '[myHighlight]' }) export class HighlightDirective { constructor(el: ElementRef, renderer: Renderer) { renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow'); } } 2 Add to module 3 use in component template @NgModule({ declarations : [ HighLight ] }) <div myHighLight > highlight me!! </div> 1 Define directive
  18. 18. Component - Replaces controller and element directive from ng1 - Can be routed to, is the page - Uses a decorator on a class to turn the class into a component myDirective my-directive component-name component-name :D ng1 naming is gone - Can be used as component on a page, part of the page
  19. 19. First component @Component({ selector : ‘component-name’, template : ` <div> content </div> `, otherprops.. }) export class SomeComponent{} <component-name> </component-name> Config object Class is decorated Use component
  20. 20. Component bind value/methods to it Input Output <my-component [user]=“user” (save)=“save( $event )” > </my-component> export class ParentComponent{ save(ev){ console.log( ‘child called save..’ ,ev.value ); } } export class ChildComponent{ @Input() user:User; @Output() save = new EventEmitter(); persist(){ this.save.emit({ value : ’data’ }); } } <div> Here is the user {{ user.name }} <input [(ngModel)]=“user.name” > <button (click)=“persist()” >Save</button> </div> Emit data Receive data Send in event 1 2 3
  21. 21. Pipes
  22. 22. Pipes <div *ngFor=“let item of items | pipe:arg”></div> export class SomePipe implements PipeTransform { value: Array<Type> = []; transform(items: Array<Type>, arg: boolean) { if (items && items.length) { this.value = items.filter((item: Type) => { return item.property == arg; }); } return this.value; } } @Pipe({ name: "pipe" }) 1 3 return matching item implement interface 2 implement transform
  23. 23. Services
  24. 24. Service - transient We DONT care about state Ex utility service export class Service { static calcSomeThing(){ return 1+1; } } import { Service } from ‘utilities/service’; export class SomeComponent{ doStuff(){ let answer = Service.calcSomething(); } } Consume service, in componentDeclare service
  25. 25. Service - singleton export class Service { getData(){ } } @injectable() import { Service } from ‘services/service’; export class SomeComponent{ construcor( private srv:Service, private other:OtherService){ } doStuff(){ var data = this.srv.getData(); } We care about state Declare Consume
  26. 26. Modules wiring up the applications
  27. 27. ngModule What modules am I dependent on What Components do I contain Bootstrap / Export if root module or feature module Services I can inject 1 2 3 @NgModule({ imports: [ BrowserModule, HttpModule ], declarations: [ AppComponent, DataComponent ], bootstrap/exports: [ AppComponent ], providers : [ srv1, srv2, srv3 ] }) export class AppModule { } 1 2 3 4 4
  28. 28. What is a module? Logical division of code Consist of Other modules Directives Services One root component = entry point for the module You can and you should write your own module to make your app e Remember OR One/ many exported component/s = that other modules may use
  29. 29. Application module overview Application module Feature module Common module Dependant on Dependant on Contains feauture directives feauture service feature pipe application wide service common component common service common pipe bootstrap exports exports
  30. 30. Application module overview Root module Feature module Common module @NgModule({ imports : [ CommonModule ], exports : [ FeatureComponent ], declarations : [ FeatureComponent, Comp1, Comp2.. ], providers : [ moduleService ] }) export class FeatureModule {} @NgModule({ imports: [ FeatureModule BrowserModule ], declarations: [ AppComponent, Pipe, Directive ], bootstrap: [ AppComponent ], providers : [ globalService ] }) export class AppModule { Dependant on Start app with Consists of Injectable srv 1 2
  31. 31. Framework modules NgIf NgFor imports Browser module Common module that defines Forms module ReactiveForms module OR
  32. 32. Lifecycle hooks Component lifecycle
  33. 33. constructor ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy There are interfaces defined that lets you hook into these events Lifecycle events for a component
  34. 34. ngOnInit, ngOnDestroy class SomeComponent implements OnInit { ngOnInit(){ // setup things like fetch init data, // listen to events etc.. } } class SomeComponent implements OnDestroy { ngOnDestroy(){ // cleanup, remove event listeners etc. } }
  35. 35. ngOnChanges when values are bound to a component class Component implements OnChanges{ @Input() data; ngOnChanges(changes: {[propertyName: string]: SimpleChange}) { for (let propName in changes) { let chng = changes[propName]; let cur = JSON.stringify(chng.currentValue); let prev = JSON.stringify(chng.previousValue); } } }
  36. 36. First project app with a few components and a service show a list of things
  37. 37. App component List component main.ts app.module.ts index.html @NgModule({ imports : [ BrowserModule ], bootstrap : [ AppComponent], declarations : [ AppComponent, ListComponent ], providers : [ ] }) export class AppModule {} Put our components in declarations so they know of each other NO services yet AppComponents is our entry point
  38. 38. app.component.ts @Component({ selector : ‘app’, template : ‘<list-component></list-component>’ }) export class AppComponent{ } App component
  39. 39. @Component({ selector : ‘list-component’ template : ` <div *ngFor=“let person of persons”> {{ person.name }} <button (click)=“select( person )” >select</bu </div> <div *ngIf=“selectedPerson” > Selected: {{ selectedPerson.name }} </div> ` }) export class ListComponent { persons:Array<Person>; selectedPerson:Person; constructor(){ this.persons = [{ name : ‘Darth Vader’ }, { name : ‘Luke Skywalker’ }, { name : ‘Yoda ’ }] List component repeater show if exist
  40. 40. Data fetching Fetch API or Rxjs Product Service Http Service WebServer GET GET Promise or Observable
  41. 41. Fetching data with fetch api and promise fetch(‘data.json',init) .then(function(response) { return response.blob(); }) var init = { method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' }; There is always this one if you don’t want to use Observables
  42. 42. import { Http } from ‘@angular/http’ @Injectable() class Service{ constructor( private http:Http ) { } getData(){ return this.http.get(url); } } Http client in angular 2 export class Component{ data; constructor( private service:Service ){ } ngOnInit(){ this.service .getData() .map( res:Response => res.json() ) .subscribe( json => this.data = json, err => console.log(err) ) } } import ‘rxjs/add/operator/map’
  43. 43. Imports So when dealing with fetching data ensure you import: The needed operator import, one for each import import ‘rxjs/add/operator/operator’ operator = do, map, catch etc.. import { Observable } ‘rxjs/Observable’ import { Http, Response } ‘@angular/http‘ Common classes
  44. 44. From promise to Observable
  45. 45. Problems with promise Not cancellable We need to write a lot of code to retry our logic, becomes messy Only returns one value Not easy to compose with other things like callbacks and event etc, although them being async in their nature Cumbersome to retry
  46. 46. A better way, observables stream of values over time 1 2 3 4 5 6
  47. 47. Observable breakdown var stream = new Rx.Observable.create( fnSuccess, fnError, fnCompleted ) stream.subscribe((data) => { console.log( “Data”,data ); }) nothing happens till someone subscribes
  48. 48. Observable under the hood var stream = Rx.Observable.create(function(observer){ observer.onNext(1); observer.onNext(2); observer.onNext(3); observer.onError( ‘there is an error’ ) }) stream.subscribe( function(data){ console.log( data ); }, function(error) { console.error( error ); } ) emit values report error 1 1 2 2
  49. 49. Observable cleaning up var homemadeStream = Rx.Observable.create((observer) => { var i=0; var handle = setInterval(function() { observer.onNext( i++ ); }, 500); return function(){ console.log('Disposing timeout'); clearTimeout( handle ); } }); var subscription2 = homemadeStream.subscribe((val) => { console.log('Homemade val',val); }); setTimeout(function() { console.log('Cancelling homemadeStream'); subscription2.dispose(); }, 1500); define dispose behaviour Call dispose
  50. 50. Observable turning something into an observable var stream = Rx.Observable.create(function(observer){ var request = new XMLHttpRequest(); request.open( ‘GET’, ‘url’ ); request.onload = function(){ if(request.status === 200) { observer.onNext( request.response ); observer.onCompleted(); } else { observer.onError( new Error( request.statusText ) ) } } request.onerror = function(){ observer.onError( new Error(‘unknown error’) ); } request.send(); }) 1 2 3 3 stream.subscribe( (result) => { console.log( result ); } err => {} () => {}) 1 3 2
  51. 51. Rich composition Create an observable from different types of sources Use operators to format the observable output
  52. 52. Everything is a stream Everything can be turned into a a stream almost click events key events data from server callbacks socket
  53. 53. DONT create observables by hand
  54. 54. Different ways to create an observable Rx.Observable.fromArray([ 1,2,3,4 ]) Rx.Observable.fromEvent(element, ‘event’); Rx.Observable.fromArray(eventEmitter, ‘data’, function(){}) Rx.Observable.fromNodeCallback(fs.createFile) Rx.Observable.fromCallback(obj.callback) Rx.Observable.range(1,3) Rx.Observable.interval(miliseconds)
  55. 55. There is an operator for that
  56. 56. var stream = Rx.Observable .interval(500) .take(5) .filter((val) = > { return val % 2 === 0; }) .map((val) => { return “val” + 1; }) Operators stream.subscribe(() => { }) operator is a function that returns an observable emit value every 500 ms limit number of values operator: change the value operator: only emit certain values
  57. 57. Operators overview 120+ operators ( 60+ Rxjs5 ) Combination Conditional Creational Error handling Filtering Transformation Utility Categories
  58. 58. How am I gonna keep track of that?
  59. 59. Start with these operators map filter flatMap switchMap do merge of interval take
  60. 60. Marble diagrams concat Stream Other stream Resulting stream 1 Most operators are covered at rxmarbles.com 2 3 4 5 1 2 3 4 5 stream/s + operation = new stream concat
  61. 61. Marble diagrams concat Stream Resulting stream 1 Most operators are covered at rxmarbles.com 2 3 1 2 3 stream/s + operation = new stream delay
  62. 62. flatMap Understand
  63. 63. flatMap Rx.Observable .of(1,2,3) .map( (val) => { } ) return Rx.DOM.getJSON( ‘data’ + val +‘.json' ) Becomes a list of observables, hard to work with Rx.Observable .of(1,2,3) .flatMap( (val) => { } ) return Rx.DOM.getJSON( ‘data’ + val +‘.json' ) Flatten all observables to a meta stream
  64. 64. flatMap in conclusion pe of streams and wants it to become something completely else like a stre clicks ajax persons Also avoid this ajax clicks ajax ajax Subscribe Subscribe Subscribe Instead become ajax clicks ajax ajax ajax personsflat map map one subscribe
  65. 65. Delay, the whole sequence stream .delay(1000) .subscribe( (val) => { var newTime = new Date().getTime(); console.log('Delayed', val + " " + (newTime - time)); }) Rx.Observable.merge( Rx.Observable.of('Marco').delay(1000), Rx.Observable.of('Polo').delay(2000) ).subscribe((val) => { var newTime = new Date().getTime(); console.log('Merged Delay', val + " " + (newTime - time)); }) Delay ….. 1 second 1 2 3 ….. 1 second Marco ….. 2 second Polo
  66. 66. Subject the double nature Observer Observable Subject the subject can act as a proxy for a group of subsc
  67. 67. Subject var subject = new Rx.Subject(); subject.subscribe((val) => { console.log( 'Produced by subject', val ); }); subject.onNext(1); subject.onCompleted(); Acts like an observer Acts like an observable
  68. 68. Subject var subject = new Rx.Subject(); var source = Rx.Observable.interval(500); source.subscribe(subject); subject.subscribe( (val) => { console.log('Sub', val); }, (err) => console.log(err), () => console.log('completed') ); setTimeout(function() { subject.onCompleted(); }, 3000); Pass subject as an observer Receives all the values pushed out by the source Able to stop receiving values 2 1 3
  69. 69. var subject = new Rx.Subject(); var source = Rx.Observable.interval(500).take(3); source.subscribe( subject ); subject.subscribe((val) => { console.log('Subject', val); }); subject.onNext('Mess1'); subject.onNext('Mess2'); setTimeout(function() { subject.onCompleted(); }, 1600); Listens to all values from source Add to stream Order important Subject onNext() before subscribe is lost subject.onNext(1);
  70. 70. var subject = Rx.ReplaySubject(); subject.onNext(1); subject.subscribe((val) = > { console.log('Replay', val); }) subject.onNext(2); subject.onNext(3); var subject = Rx.Subject(); subject.onNext(1); subject.subscribe((val) = > { console.log('Replay', val); }) subject.onNext(2); subject.onNext(3); Normal subject, everything before subscribe is lost Replay subject, nothing is lost Subject - typesdont do this 1 2
  71. 71. BehaviourSubject Good for default values /* Initialize with initial value of 42 */ var subject = new Rx.BehaviorSubject(42); var subscription = subject.subscribe( function (x) { console.log('Next: ' + x.toString()); }, function (err) { console.log('Error: ' + err); }, function () { console.log('Completed'); }); subject.onNext(56); subject.onCompleted(); // => Completed Init/Default value Next: 42 Next: 56
  72. 72. Schedulers bending time
  73. 73. Because scheduler has its own virtual clock Anything scheduled on that scheduler will adhere to time denoted on the clock I.e we can bend time for ex unit testing
  74. 74. var onNext = Rx.ReactiveTest.onNext; var scheduler = new Rx.TestScheduler(); var subject = scheduler.createColdObservable( onNext(100,'first'), onNext(200,'second') ); var result; subject.subscribe((val) => { result = val; }); scheduler.advanceBy( 100 ); console.log('Should equal', result === 'first'); scheduler.advanceBy( 100 ); console.log('Should equal', result === 'second'); Advance time Assert Advance time Assert create observable from scheduler emit values
  75. 75. var testScheduler = new Rx.TestScheduler(); var stream = Rx.Observable.interval(1000, testScheduler) .take(5) .map((val) => { return val + 1 }) .filter((i) => { return i % 2 === 0 }); var result; stream.subscribe((val) => result = val ); console.log('testing function’); testScheduler.advanceBy(1000); testScheduler.advanceBy(1000); testScheduler.advanceBy(1000); console.log('Should equal', result === 2); testScheduler.advanceBy(1000); testScheduler.advanceBy(1000); console.log('Should equal', result === 4); replace default scheduler 0 1 2
  76. 76. Further reading https://xgrommx.github.io/rx-book http://www.learnrxjs.io/ bacon.js
  77. 77. Back to angular 2 and some recipes
  78. 78. flatMap auto complete flatmapExample = Rx.Observable.fromEvent(input,'keyup') .map( function(ev){ return ev.target.value; }) .filter(function(text){ return text.length >=3; }) .distinctUntilChanged() .flatMap( function(val){ return Rx.DOM.getJSON( 'data3.json' ); }) flatmapExample.subscribe( function(result){ console.log('Flatmap', result); }) Transform event to char Wait until we have 3 chars Only perform search if this ‘search’ is unique
  79. 79. Debounce stop clicking the save button var debounceTime = Rx.Observable .fromEvent(button,'click') .debounce(2000); debounceTime.subscribe( function(){ console.log('mouse pressed'); }) Ignores all generated mouse click events for 2 seconds click click click click click ignore ignore ignore ignore use …. 2 seconds passed
  80. 80. Retry for those shaky connections var stream = Rx.DOM.get(‘/products.json’) .delay( 5000 ) .retry(5); stream.subscribe((val) => { console.log('Data', val); }, err => console.log(err)); 5 failed attempts then we hit error callback Its so easy to retry, imagine how messy this code would be with a promise
  81. 81. Component to Component You want something that can produce value, that you can listen to this.subject = new Rx.Subject(); function sendData(data){ this.subject.next( data ) } function getSubject(){ return this.subject; } //service impl Component1 Component2 service.getSubject().subscribe(()=>{}) service.sendData( data ) BUT, can be made nicer with a uniform data flow
  82. 82. Routing setup NgModule({ imports : [ BrowserModule … other modules RouterModule ], declarations : [ AppComponent, … other components ], bootstrap : [ AppComponent ] }) export class AppModule {} import { RouterModule } from ‘@angular/router’ Router service Router directives and our configured routes contains
  83. 83. Routing component based [ { path : ‘jedis’, component : JediListComponent, }, { path : ‘jedis/:id’, component : JediComponent, }, { path : ‘’, redirect : ‘jedis’, pathMatch: ‘full’ }, { path : ‘**’, component : PageNotFoundComponent, } ] domain/jedis domain/jedis/1 domain/anything Order matters, first match wins
  84. 84. Routing setting up configured routes NgModule({ imports : [ BrowserModule … other modules RouterModule.forRoot([ [{ path: ‘jedis’, component : ‘JediList’ }] .. and so on ]) ], declarations : [ AppComponent, … other components ], bootstrap : [ AppComponent ] }) export class AppModule {}
  85. 85. Routing directives <a [routerLink]=“[ ‘/jedis’ ]” >Jedis</a> { path: ‘jedis’, component : ‘JediList’ } <router-outlet> </router-outlet> Where to render content, think ng-view Creates a link using routerLink attribute directive Corresponding configured route
  86. 86. Routing with parameters { path: ‘jedis/:id’, component : ‘JediDetail’ } <a [routerLink]=“[ ‘/jedis’, jedi.id ]” >{{ jedi.name }}</a> <div *ngFor=“let jedi of jedis”> </div> import { ActivatedRoute } from ‘@angular/route’; export class JediDetail{ constructor(private route:ActivatedRoute){ this.route.snapshot.params[‘id’]; // get data by id } }
  87. 87. Routing routing service import { Router } from ‘@angular/router’ export class JediDetailComponent{ constructor( router:Router ) { } onSave(){ this.service .save( someData ) .subscribe((result) => { this.router.navigate([‘/jedis’]); }) } } this.router.navigate([‘url’,<parameter>]);
  88. 88. Routing guards CanActivate CanDeactivate Resolve CanLoad Is it allowed to navigate to this route Is it allowed to navigate away from this route Prefetch data before going to the route Prevent async routing
  89. 89. CanActivate example export class AuthenticateGuard implements CanActivate { constructor( private user:User ){ } canActivate():boolean { return this.user.roles.contains(‘Administrator’); } } RouterModule.forRoot([ { path: ’adminpage’, canActivate : [ AuthenticateGuard ], component : AdminPageComponent } ])
  90. 90. angular-cli forms augury Further reading angular- universal AOT compilation scaffolding tool debug tool for browser very competent way of dealing with forms and validation serverside rendering precompilation of code, faster, smaller bundle, no JIT, no compiler in bundle
  91. 91. Thank you

×