angular

Let's get reactive

❤︎

by Wassim Chegham — @manekinekko

😍

let's talk about state 

management in your ui with angular and rxjs...

Wassim Chegham

Developer Advocate

@manekinekko

how did things work 

in angularjs?

view

model

digest loop

what's the issue with this architecture?

performance complexity

side effects

I have no idea what changed, so I will just check everything that may need updating — $digest

ANGULARJS DIRTY CHECKING

what about angular?

angular

is paradigm

agnostic

model  view  controller

model/view  view/model

model  view  intent

reactive  programming—FRP

you choose

functional

reactive

programming

FRP is a programming paradigm for 

asynchronous dataflow programming using the building blocks of functional programming 

(e.g. map, reduce, filter) [...]

 

FRP has been used for programming GUI, 

robotics, and music, aiming to simplify these problems by explicitly modeling time [...] 

FRP has taken many forms since itS

introduction in 1997 [...]

wikipedia

asynchronous dataflow

Functional programming

MOdeling

time

STREAMSTREAMSTREAM
STREAMSTREAMSTREAM
STREAMSTREAMSTREAM

STREAMSTREAMSTREAM
STREAMSTREAMSTREAM
STREAMSTREAMSTREAM

STREAmSTREAMSTREAM
STREAMSTREAMSTREAM
STREAMSTREAMSTREAM

STREAMSTREAMSTREAM

A STREAM IS A SEQUENCE OF ONGOING

 

"ASYNCHRONOUS events"

 

ORDERED IN TIME

in other words

CLICK

EVENT

KEY

EVENT

XHR

EVENT

ERROR

END

THIS IS A TIMELINE

THIS IS A STREAM

how to work with streams?

RXJS

with

reactive extensions for javascript

rxjs is

&

an implementation of observables

OBSERVABLES are like PROMISES OBSERVABLES ARE NOT PROMISES 

BUT they are asynchronous

 

OBSERVABLES ARE LIKE ARRAYS

OBSERVABLES ARE noT arrays  

BUT THEY ARE iterables

observables are

create stream

COMBINE STREAMS​

transform STREAMS

subscribe to STREAMS

         "react" to changes

observables can

methods that perform computations on the values

observables have operators

E.G. MAP, REDUCE, FILTER, scan, zip, delay, debounce, throttle... and many more

a simple example

import "rxjs/add/observable/range";
import "rxjs/add/operator/filter";
import "rxjs/add/operator/map";
import "rxjs/add/operator/scan";

range(0, 10)


  .filter(x => x % 2 === 0)
  .map(x => x + x)
  .scan((acc, x) => acc + x, 0)



  .subscribe(x => console.log(x));

create a stream

transform it

subscribe to it

import { range } from "rxjs/observable/range";
import { map } from "rxjs/operators/map";
import { filter } from "rxjs/operators/filter";
import { scan } from "rxjs/operators/scan";

range(0, 10)

  .pipe(
    filter(x => x % 2 === 0), 
    map(x => x + x), 
    scan((acc, x) => acc + x, 0)
  )


  .subscribe(x => console.log(x));

how does Angular use observables?

an angular app is

a reactive app 

reminder

core • forms • router • HTTP... 

working with forms (1/3)

@Component({
  selector: 'model-driven-forms',
  template: `
    <form (ngSubmit)="onSubmit()" [formGroup]="mdf">
        <label for="email">Email</label>
        <input type="email" formControlName ="email">
        <label for="comments">Comments</label>
        <textarea formControlName ="comments"></textarea>
    </form>
  `
})
class ModelDrivenForms {
  
  mdf: FormGroup;

  constructor(fb: FormBuilder) {
    this.mdf = fb.group({
      'email': ['', Validators.required],
      'comments': ['']
    });
  }
}
// import {map, filter} from 'rxjs/operators';

this.mdf.valueChanges
    .pipe(
        map( value => {
            value.email = this.sanitize(value.email);
            return value;
        }),
        filter( value => this.form.valid)
    )
    .subscribe( value => print(`
        Model Driven Form valid value: 
        vm = ${JSON.stringify(value)}
    `));

working with forms (2/3)

// import {map, flatMap} from 'rxjs/operators';

this.mdf.ngSubmit
  .pipe(
    map( _ => this.mdf.controls['email'] ),
    flatMap( _ => /* push to server */)
  )
  .subscribe(
    value => console.log(value),
    error => console.trace(error),
   () => console.info('done')
  )

working with forms (3/3)

http simple (1/2)

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Config} from './app.config';

interface ItemsResponse { ... }

@Injectable()
class Fetch {
    //...
    constructor(private http: HttpClient) {

      this.stream$ = this.http.get<ItemsResponse>(Config.DATA_URL);

    }
    //...
}

http Advanced (2/2)

// other imports ...

import {interval} from 'rxjs/observable/interval';
import {map, flatMap, startWith, toArray} from 'rxjs/operators';

@Injectable() class Fetch {
    contructor(loader: FetcherService) {
      this.stream$ = interval(Config.TIMER)
        .pipe(
            flatMap(_ => loader.fetch()),
            map((facts: any) => this.randomize(facts.data))
        )
        .subscribe(
          data => this.randomQuote = data,
          err => this.logError(err),
          () => console.log('Random Quote Complete')
        );
    }
    //...
}

event emitter (1/3)

event emitter (2/3)

import {Component} from '@angular/core';

@Component({
    selector: 'parent-cmp',
    template: `<child-cmp 
                (onChildEvent)="receiveChildEvent($event)">
               </child-cmp>`
})
export class ParentComponent {

  receiveChildEvent(value) {
    console.log(value);
  }

}

event emitter (3/3)

import {Component, Output, EventEmitter} from '@angular/core';

@Component({
    selector: 'child-cmp'
    /* configuration */
})
export class ChildCmp {

  @Output() outputEvent: EventEmitter<string>;

  constructor() {
    this.outputEvent = new EventEmitter<string>();
    this.outputEvent.emit('foo');
  }

}

angulaR

observables

@manekinekko