Skip to content

useFormPending

Returns whether a FormGroup has pending async validators as a signal. The signal updates reactively whenever the form's pending state changes.

Usage

typescript
import { useFormPending } from 'ng-reactive-utils';

@Component({
  template: `
    <form [formGroup]="form">
      <input formControlName="username" placeholder="Username" />

      @if (isPending()) {
        <span class="loading">Checking availability...</span>
      }

      <button [disabled]="isPending()">
        @if (isPending()) {
          Validating...
        } @else {
          Submit
        }
      </button>
    </form>
  `,
})
class RegistrationComponent {
  form = new FormGroup({
    username: new FormControl('', [], [this.usernameValidator()]),
  });

  isPending = useFormPending(this.form);

  usernameValidator(): AsyncValidatorFn {
    return (control) => {
      return this.userService
        .checkUsername(control.value)
        .pipe(map((exists) => (exists ? { usernameTaken: true } : null)));
    };
  }
}

Parameters

ParameterTypeDefaultDescription
formFormGrouprequiredThe FormGroup to check pending state for

Returns

Signal<boolean> - A readonly signal containing the pending state (true if async validators are running)

Notes

  • Uses toSignal with form.statusChanges observable
  • Returns true when any control has running async validators
  • Returns false when all async validators have completed
  • Useful for showing loading indicators during async validation

Source

ts
import { Signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FormGroup } from '@angular/forms';
import { map } from 'rxjs';

/**
 * Returns whether a FormGroup has pending async validators as a signal.
 * The signal updates reactively whenever the form's pending state changes.
 *
 * @param form - The FormGroup to check pending state for
 * @returns A signal containing the pending state (true if async validators are running)
 *
 * @example
 * ```typescript
 * @Component({
 *   template: `
 *     <form [formGroup]="form">
 *       <input formControlName="username" />
 *       @if (isPending()) {
 *         <span>Checking availability...</span>
 *       }
 *     </form>
 *   `
 * })
 * class MyComponent {
 *   form = new FormGroup({
 *     username: new FormControl('', [], [asyncUsernameValidator])
 *   });
 *   isPending = useFormPending(this.form);
 * }
 * ```
 */
export const useFormPending = (form: FormGroup): Signal<boolean> => {
  return toSignal(form.statusChanges.pipe(map(() => form.pending)), {
    initialValue: form.pending,
  }) as Signal<boolean>;
};

Released under the MIT License.