Angular: Leveraging RxJS for combining Action and Data streams

When it comes to streams, there are 2 types:

1.       Data Stream: Mostly HTTP calls where you get a response to a request. And its complete!

               

2.       Action stream: button clicks, drop down selections, check box selections etc where values are emitted continuously, you keep getting new values into a stream  

       Stackblitz links:

         https://stackblitz.com/edit/angular-ivy-o41hzu

         https://stackblitz.com/edit/angular-ivy-pdkt1s  

         https://stackblitz.com/edit/angular-ivy-hlt1u1 (get posts for user name entered)


Consider you have 2 components:

1.       List Component: One to display the list of emails

2.       Detail Component: Displays the post of the selected email from list component

So, our app.component.html looks like this:

<list-component></list-component>

<detail-component></detail-component>

 

INTERFACE

export interface IComment {

  postId: Number;

  id: Number;

  name: String;

  email: String;

  body: String;

}

 

SERVICE:

Let’s design services in a “declarative” style rather than functional style. So, you will now have an observable instead of a function returning an observable

getComments$ = this._http

    .get<IComment[]>(`https://jsonplaceholder.typicode.com/comments`)

    .pipe(

      map(response => response),

      catchError(err => of('error', err))

    );

 

LIST COMPONENT

<select *ngIf="(comments$ | async) as comments">

       <option *ngFor="let comment of comments"> {{ comment.email }}</option>

 </select>

comments$: Observable<IComment[]>;

  ngOnInit() {

    this.comments$ = this._appService.getComments$;

  }

DETAIL COMPONENT

Now, we need to capture the selected email from list. Let’s make a small update to out list component to capture this

List.component.ts:

<select *ngIf="(comments$ | async) as comments" [(ngModel)]="selectedEmail" (change)="onEmailChanged(selectedEmail)">

        <option *ngFor="let comment of comments" [value]="comment.email">{{ comment.email }}</option>

 </select>

 

onEmailChanged(e) {

    this._appService.updateEmailSelection(e);

  }

 

ADDING SUBJECT IN SERVICE

Now this selection of email from list is an “action stream”. You need this stream to emit new data so that you can capture this in details component.

A subject is a special type of stream that acts both as observer and an observable. You can “next” new data and also “subscribe” to it when new data is added to the stream.

Both Subject and Behavior subject are same except a Behavior Subject has to have a default/initial value.

private selectedEmail = new Subject(); //observer

selectedEmailObs$ = this.selectedEmail.asObservable(); //observable

updateEmailSelection(email) {

    this.selectedEmail.next(email); //list component updates this when new email selected

 }

 

ADDING DETAILS STREAM IN SERVICE

getDeatils$: Observable<IComment[]> = combineLatest([

    this.selectedEmailObs$

  ]).pipe(

    switchMap(([emailID]) => {

      return this._http.get<IComment[]>(

        `https://jsonplaceholder.typicode.com/comments?email=${emailID}`

      );

    })

  );

 

All you need to do is capture this stream and display the data using async pipe like before:

<div *ngIf="(details$ | async) as details">

      <div *ngFor="let d of details">

        Name: {{ d.name }} ,{{d.body }}

    </div>

 </div>

 

details$: Observable<IComment[]>;

  ngOnInit() {

    this.details$ = this._appService.getDeatils$;

  }


OUTPUT:



Comments

Popular posts from this blog

Inside the JavaScript Memory Box: Visualizing Variables, References, and Copies

React & State Management: All Concepts

React: Communication between components