Reactive Programming in Angular

Angular JAX

What is Reactive programming?

Entire programs can be built uniquely around the notion of streams.

 

 

RxJS

WTF is RxJS?

RxJS

RxJS is a library for composing asynchronous and event based programs by using observable sequences.

+

= POWER COUPLE

Why RxJS?

Compositional: Our view requires data from several sources, we can easily compose data with RxJS.

Watchful: We get notified when our data changes overtime.

Lazy: doesn't start until we subscribe

Error Handler: handle errors

Cancel: We can cancel async actions

Benefits of Reactive programming

Quick to react to user interactions, resistant to failure, reactive to state changes (code watches for state changes and reacts)

RxJS Observable Streams

-Subscribe

RxJS Observable Streams

-Pipe through set of operators

-Observer( next, error(), complete)

-Stop steam (unsubscribe)

Ways to stop an Observable

-Call .complete()

-Use a completing operator

-Throw error
 

-Unsubscribe

Of() and from()

Observable.of([1, 2, 3]).subscribe(x => console.log(x));
//Would print the whole array at once.

///On the other hand, from prints elements one by one.

Observable.from([1, 2, 3]).subscribe(x => console.log(x));

Of() and from()

Convert Promise to Observable

getPosts(query?: object): Post[] {
    return from(
      this.cdaClient.getEntries({
        ...Object,
        content_type: this.CONFIG.contentTypeIds.angularPost,
        query
      })
    ).pipe(map(posts => posts.items));
  }

RxJS Operators

map Operator

const source = from([1, 2, 3, 4, 5]);
//add 10 to each value
const example = source.pipe(map(val => val + 10));
//output: 11,12,13,14,15

map Operator

tap

const source = of(1, 2, 3, 4, 5);

const example = source.pipe(
  tap(val => {
    val = val * 2; 
    console.log(`On tap: ${val}`);
    //What is the output?
  }),
);

const subscribe = example.subscribe(val => console.log(val));
//What is the output?

take

take

//emit 1,2,3,4,5
const source = of(1, 2, 3, 4, 5);
//take the first emitted value then complete
const example = source.pipe(take(1));
//output ?

Handling Errors

CatchError

import { timer, from, of } from 'rxjs';
import { mergeMap, catchError } from 'rxjs/operators';

//Some code
const example = source.pipe(
  mergeMap(_ =>
    from(myBadPromise()).pipe(catchError(error => of(`Bad Promise: ${error}`)))
  )
);
//output: 'Bad Promise: Rejected'
//Rejected is the value that the stream contains
const subscribe = example.subscribe(val => console.log(val));

Catch and Replace

  categories$ = this.productCategoryService.productCategories$.pipe(
    catchError(err => {
      this.errorMessageSubject.next(err);
      return EMPTY;
    })
  );
<div class="alert alert-danger" *ngIf="errorMessageSubject | async as errorMessage">
  {{ errorMessage }}
</div>

Catch and Rethrow

this.httpPost.pipe(switchMap(res => (res.bearerToken) ? 
     of(this.saveJwt(res.bearerToken)) : 
     throwError('Valid token not returned')
));

Scan

Text

Text

Scan

const source = of(1, 2, 3);
// basic scan example, sum over time starting with zero
const example = source.pipe(scan((acc, curr) => acc + curr, 0));
// log accumulated values
// output: 1,3,6

Caching with RxJS

-Improves responsiveness

-Reduces bandwidth and network consumption

-Reduces backend server load

-Reduces redundant computations

shareReply

//You first get the observable for data:

 ngOninit(){
    this.data$ =  this._jokeService.getData().pipe(shareReplay(1));
 }
//Now subscribe multiple times:

 public getData(){
     this.data$.subscribe();
 }
//Your service:

public getData() {
    return this.http.get(API_ENDPOINT);
}

if caching

 

 

-Invalidating the cache on a time interval

 

-Allowing user to control when the data is refreshed

-Always getting refresh data on update

Declarative Approach

 

 

Declarative Approach

 

 products$ = this.http.get<Product[]>(this.productsUrl).pipe(
    tap(data => console.log('Products: ', JSON.stringify(data))),
    catchError(this.handleError)
 );
getProducts(): Observable<Product[]> {
  return this.http.get<Product[]>(this.productsUrl).pipe(
    catchError(this.handleError)
  );
} 


 

-Leverage the power of Rxjs observables and operators

Benefits of DA

 

-Effectively combine streams

-Easy share observables

-Readily react to user action

Why Combine Streams?

-Map Id to a string

-Work with multiple data sources

-React to actions

-Simply template code

combineLatest

forkJoin

lastestFrom

-LatestFrom: emits any time a new value is emitted from the source stream

Recap

-CombineLast: emits any time a new value is emitted from any of the sources them

-ForkJoin: Emits only the last emitted values

Higher Order Observable

DON'T DO

of(3,7).pipe(map id=> this.http.get<Supplier>)(`....${id}`))).subcribe();


of(3,7).pipe(map id=> this.http.get<Supplier>)(`....${id}`))).subcribe(o=> o.subscribre());

concatMap

concatMap

 supplierWithConcatMap$ = of(1, 5, 8).pipe(
    tap(id => console.log('concat id ', id)),
    concatMap(id => this.http.get<Supplier>(`${this.suppliersUrl}/${id}`))
  );

mergeMap

mergeMap

supplierWithMergeMap$ = of(1, 5, 8).pipe(
    tap(id => console.log('merge id ', id)),
    mergeMap(id => this.http.get<Supplier>(`${this.suppliersUrl}/${id}`))
  );

switchMap

switchMap

  supplierWithSwitchMap$ = of(1, 5, 8).pipe(
    tap(id => console.log('swtich id ', id)),
    switchMap(id => this.http.get<Supplier>(`${this.suppliersUrl}/${id}`))
  );

Resources

RxJS

By Patricio Vargas

RxJS

Reactive programming in Angular using RxJS

  • 177