Form Status & Error Display

valid, invalid, dirty, touched, pristine

Form Status & Error Display

Each control tracks its own status. Use those flags to show errors at the right time and to reset or patch values cleanly.

4 min read Level 2/5 #angular#forms#status
What you'll learn
  • Read valid, invalid, dirty, touched, pristine
  • Show errors after blur (touched)
  • Reset and patch values

A FormControl is more than a value. It also tracks how the user has interacted with it. Knowing the difference matters for UX.

The Status Flags

FlagMeaning
validPasses every validator
invalidFails at least one validator
pendingAsync validator is running
pristineValue has not changed from initial
dirtyValue has changed at least once
untouchedUser has not blurred this control yet
touchedUser has blurred this control
disabledExcluded from validation and the form value

Show Errors at the Right Time

Showing “Required” on a field the user has not even visited is annoying. Gate error messages on touched.

@let emailCtrl = form.controls.email;

<input formControlName="email" />

@if (emailCtrl.invalid && (emailCtrl.touched || submitted())) {
  <p class="err">Please enter a valid email.</p>
}

When the form is submitted, you typically want to surface every error — markAllAsTouched() is the helper.

submit() {
  if (this.form.invalid) {
    this.form.markAllAsTouched();
    return;
  }
  this.api.save(this.form.value).subscribe();
}

Updating Values

  • form.setValue({ ... }) — replace the full value. Every field must be present, type-checked.
  • form.patchValue({ ... }) — replace some fields. Missing keys are ignored.
  • form.reset() — back to the initial state, also clears touched/dirty flags.
  • form.reset({ email: 'a@b.com' }) — reset to a custom starting point.

Disabling Fields

control.disable() and control.enable() toggle a control. Disabled controls are not included in form.value — pass { emitEvent: false } if you do not want the change to fire valueChanges.

Typed Forms →