Day 4 of 5
⏱ ~60 minutes
Angular in 5 Days — Day 4

Reactive Forms

Angular Reactive Forms give you full programmatic control over form state, validation, and submission. This lesson covers FormBuilder, Validators, custom validators, and wiring up error messages.

Setting Up Reactive Forms

Import ReactiveFormsModule in your module, then build forms in the component class using FormBuilder.

app.module.ts
imports: [ReactiveFormsModule]
registration.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({ selector: 'app-registration', templateUrl: '...' })
export class RegistrationComponent {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      name: ['', [Validators.required, Validators.minLength(2)]],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(8)]],
      confirmPassword: ['', Validators.required]
    }, { validators: this.passwordMatch });
  }

  // Custom cross-field validator
  passwordMatch(group: FormGroup) {
    const pw = group.get('password')?.value;
    const confirm = group.get('confirmPassword')?.value;
    return pw === confirm ? null : { mismatch: true };
  }

  get nameControl() { return this.form.get('name'); }

  onSubmit() {
    if (this.form.valid) {
      console.log(this.form.value);
    } else {
      this.form.markAllAsTouched();
    }
  }
}
registration.component.html
Name is required. At least 2 characters.
Passwords don't match.
💡
Access control state without the getter boilerplate: form.get('email')?.errors?.['email']. The ?. optional chaining prevents errors when the control hasn't been touched yet.
📝 Day 4 Exercise
Build a Contact Form with Validation
  1. Create a contact form with: name (required, min 2), email (required, valid email), subject (required), message (required, min 20 chars).
  2. Show inline error messages under each field, only after the field has been touched.
  3. Add a character counter for the message field using valueChanges observable.
  4. Disable the submit button until the form is valid.
  5. On submit, log the form value and reset the form.

Day 4 Summary

  • FormBuilder.group() creates a FormGroup with controls and validators.
  • Built-in validators: required, email, minLength, maxLength, pattern.
  • Show errors only when control.invalid && control.touched to avoid red fields on page load.
  • Cross-field validators go at the group level, not the control level.
Finished this lesson?