RxJS 6 Patterns with Angular Material: Refresh Button

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.

TypeScript
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. If refresh$ 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.

HTML
<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.

HTML
<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!

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.