In this article, we’ll be looking at a very simple RxJS 6 pattern that allows us to easily refresh data coming from REST APIs (or any other async data source).
In Angular, we’ll be using a service to handle most of the work, including the data fetching and the refresh logic.
Let’s look at a mock service that we’ll be using to fetch some data from a REST API.
export class MockService {
refresh$ = new ReplaySubject(1);
data$: Observable<SomeDataType>;
constructor(private http: HttpClient) {
this.refresh();
this.data$ = this.refresh$.pipe(
switchMap(() => this.getData()),
share()
);
}
refresh() {
this.refresh$.next();
}
// This one could also be private
getData(): Observable<SomeDataType> {
return this.http.get<SomeDataType>(`url`);
}
}
Explanation
As you can see in line 3, we’re using a ReplaySubject with a buffer of 1 as a trigger for the refresh logic. This is almost the same as using a BehaviorSubject
, but we can avoid passing an actual value to the next
function.
Our data$
observable is triggered every time we emit a value on the refresh$
subject. Since the ReplaySubject
doesn’t have an initial value, on line 8 we call the refresh
function to emit one value before anything else.
After that, I’m using switchMap to subscribe to the http call observable. This is just one of the alternatives to chain the API call to our refresh button:
- switchMap will begin a request every time
refresh$
emits. Ifrefresh$
emits again before the current request is completed, the current request is canceled and a new one is issued. - exhaustMap will discard
refresh$
values if there is a pending request. - concatMap will begin a request every time
refresh$
emits without overlaps (a new one will begin only after the previous one completes). - mergeMap will begin a request every time
refresh$
emits and allows concurrency.
Usage
You can create a refresh button like the following and place it in any component that can access your service.
<button mat-icon-button aria-label="Refresh"
(click)="mockService.refresh()">
<mat-icon>refresh</mat-icon>
</button>
You can then subscribe to the data$ observable directly from your HTML template.
<div *ngIf="mockService.data$ | async as data">
{{data}}
</div>
Conclusion
This article explained a very simple way to handle data refresh with RxJS in Angular.
You should be able to implement it in your project with minimal effort, even if you’re not using Angular Material.
If you think I’ve missed something or have a better solution, please let me know!