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
Post a Comment