RxJS 6 Patterns with Angular Material: Confirmation Dialog

Intro

This basic pattern applies to RxJS 6 in combination with Angular Material. However, it can be applied to any other environment that supports RxJS 6, as long as you have an observable-based dialog implementation.

Desired behaviour

  1. A user clicks on a button
  2. A confirmation dialog is shown
  3. If the user confirms, an action is performed

RxJS Solution

First of all, we need a way to trigger the action. In this case I’m using a generic Subject, since I don’t need any value to be passed or stored. In your component’s TypeScript code, add this variable.

TypeScript
confirmAndDoAction$ = new Subject();

In your component’s HTML, create a button to emit values with the Subject we created.

HTML
<button mat-button (click)="confirmAndDoAction$.next()">
    PERFORM ACTION
</button>

We also need an actual dialog to show. Let’s create a basic component (ng g c confirm-dialog) and edit the HTML. It should look something along these lines.

HTML
<h2 mat-dialog-title>Confirm operation</h2>
<mat-dialog-content class="mat-typography">
  <p>Do you confirm this operation?</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
  <button mat-button mat-dialog-close cdkFocusInitial>NO</button>
  <button mat-button [mat-dialog-close]="true">YES</button>
</mat-dialog-actions>

Notice that we return true when the user clicks OK.
Now we can create our observable pipeline. In your component’s TypeScript code, add these lines and customize them to your needs.

TypeScript
ngOnInit(): void {
	this.confirmAndDoAction$.pipe(
	  exhaustMap(() => this.dialog.open(ConfirmDialogComponent).afterClosed()),
	  filter((response) => response),
	  concatMap((value) => yourObservableAction())
	).subscribe();
}

Remember that you must unsubscribe from this observable. There are many ways to do it, and I suggest you find the one that makes sense for your project.

What’s going on?

Each time confirmAndDoAction$ emits, the following happens:

  1. exhaustMap is a very useful operator, especially with buttons. After it’s triggered, it ignores subsequent emissions until the inner observable completes. In this case, it ignores further clicks until the dialog is dismissed. This is very useful to prevent double clicks.
  2. The chain subscribes to the dialog observable and waits for it to complete. This happens as soon as a user dismisses the dialog. It only returns true if the user clicks OK.
  3. filter only emits values that match the condition. In this case, the execution proceeds only if response is true.
  4. concatMap is one of the operators that you can use here. If you reached this point, you can perform the action. You can also replace it with tap and do some basic operations that don’t require observables.

Conclusion

This was a very simple but useful pattern that leverages RxJS to handle asynchronous user interactions. 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.