How to use exhaustMap operator in Angular

The exhaustMap operator is crucial for preventing overlapping requests in Angular, ensuring that new emissions are ignored while an inner observable is still executing. With over 25 years of experience building enterprise applications and as the creator of CoreUI, I use exhaustMap to prevent duplicate form submissions and API calls. The most effective use case is for form submissions where you want to ignore subsequent submit attempts until the current request completes. This prevents race conditions and duplicate operations that could corrupt data or create inconsistent application state.

Use exhaustMap to ignore new emissions while an inner observable is active, perfect for preventing duplicate form submissions and API calls.

import { Component } from '@angular/core'
import { FormBuilder, FormGroup, Validators } from '@angular/forms'
import { exhaustMap, tap } from 'rxjs'
import { UserService } from './user.service'

@Component({
  selector: 'app-user-form',
  template: `
    <form [formGroup]="userForm" (ngSubmit)="onSubmit()">
      <input formControlName="name" placeholder="Name">
      <input formControlName="email" placeholder="Email">
      <button type="submit" [disabled]="isSubmitting">
        {{ isSubmitting ? 'Saving...' : 'Save User' }}
      </button>
    </form>
  `
})
export class UserFormComponent {
  userForm: FormGroup
  isSubmitting = false

  constructor(
    private fb: FormBuilder,
    private userService: UserService
  ) {
    this.userForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]]
    })
  }

  onSubmit() {
    if (this.userForm.valid) {
      this.userForm.valueChanges.pipe(
        exhaustMap(() => {
          this.isSubmitting = true
          return this.userService.createUser(this.userForm.value).pipe(
            tap(() => this.isSubmitting = false)
          )
        })
      ).subscribe({
        next: (response) => console.log('User created:', response),
        error: (error) => this.isSubmitting = false
      })
    }
  }
}

This implementation uses exhaustMap to prevent multiple simultaneous form submissions. When the user clicks submit rapidly, only the first click triggers the API call, and subsequent clicks are ignored until the request completes. The isSubmitting flag provides visual feedback by disabling the button and changing its text during the request.

Best Practice Note:

This exhaustMap pattern is used in CoreUI’s form components to prevent data corruption from duplicate submissions. Always combine exhaustMap with loading states and proper error handling to provide clear feedback to users about request status.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author