Form Validation and State

Back

Loading concept...

🎯 Angular Form Validation: Your Guard Dogs for Perfect Data

Imagine this: You’re building a castle (your app), and forms are the gates where visitors (users) enter information. But not everyone should get in! Some might forget their name, others might give fake emails. Validators are your loyal guard dogs — they check every visitor before letting them through!


🏰 The Castle Gate Analogy

Think of your form like a castle entrance:

  • The Gate = Your Form
  • Guard Dogs = Validators
  • Visitors = User Input
  • Castle Rules = Validation Rules

Each guard dog has a job:

  • One checks if visitors said their name (required)
  • One checks if the email looks real (email pattern)
  • One even calls the kingdom database to verify! (async)

🐕 Built-in Validators: Your Ready-Made Guard Dogs

Angular gives you guard dogs right out of the box! No training needed.

The Main Pack

Guard Dog What It Checks Example
required “Did you say something?” Name field can’t be empty
email “Is this a real email shape?” must@have.dots
minLength “Is it long enough?” Password ≥ 8 chars
maxLength “Not too long!” Username ≤ 20 chars
min “Number big enough?” Age ≥ 18
max “Number not too big?” Quantity ≤ 100
pattern “Does it match my rules?” Only letters allowed

🎬 See It In Action

import { Validators } from '@angular/forms';

// Creating a form with guard dogs
this.userForm = this.fb.group({
  name: ['', [
    Validators.required,    // Must fill this!
    Validators.minLength(2) // At least 2 letters
  ]],
  email: ['', [
    Validators.required,
    Validators.email        // Must look like email
  ]],
  age: ['', [
    Validators.min(13),     // Must be 13+
    Validators.max(120)     // Not a vampire!
  ]]
});

💡 Quick Tip

Think of Validators.required as a guard dog that barks: “Hey! You can’t enter without telling me your name!”


🎨 Custom Validators: Training Your Own Guard Dogs

Sometimes the built-in dogs aren’t enough. What if you need a dog that checks if a password has BOTH letters AND numbers?

You train your own!

Recipe for a Custom Validator

// A guard dog that checks for
// at least one number in password
function hasNumber(control: AbstractControl)
  : ValidationErrors | null {

  const value = control.value;
  const hasNum = /[0-9]/.test(value);

  // null = "All good, let them in!"
  // object = "STOP! Problem found!"
  return hasNum ? null : { noNumber: true };
}

Using Your Custom Dog

this.form = this.fb.group({
  password: ['', [
    Validators.required,
    Validators.minLength(8),
    hasNumber  // Our custom guard dog!
  ]]
});

🎯 The Return Value Secret

✅ return null        → "Visitor approved!"
❌ return { error }   → "STOP! I found a problem!"

⏳ Async Validators: The Detective Dogs

Some checks take time. Like calling a server to see if a username is already taken. These are async validators — detective dogs that go investigate!

graph TD A["User types username"] --> B["Async Validator Starts"] B --> C["🔍 Checks server..."] C --> D{Username exists?} D -->|Yes| E["❌ Error: taken"] D -->|No| F["✅ All clear!"]

Building a Detective Dog

function checkUsername(
  http: HttpClient
): AsyncValidatorFn {
  return (control: AbstractControl) => {
    return http.get(`/api/check/${control.value}`)
      .pipe(
        map(exists =>
          exists ? { taken: true } : null
        ),
        catchError(() => of(null))
      );
  };
}

Using It (Note: 3rd parameter!)

this.form = this.fb.group({
  username: [
    '',                    // initial value
    [Validators.required], // sync validators
    [checkUsername(http)]  // async validators!
  ]
});

🕐 The Pending State

While the detective dog investigates:

<span *ngIf="username.pending">
  Checking availability...
</span>

🤝 Cross-Field Validation: Team of Dogs

Sometimes one field depends on another. Like checking if “password” and “confirm password” match!

One dog can’t do this alone — they need teamwork!

The Password Match Team

function passwordsMatch(
  group: AbstractControl
): ValidationErrors | null {
  const pass = group.get('password')?.value;
  const confirm = group.get('confirmPass')?.value;

  return pass === confirm
    ? null
    : { passwordMismatch: true };
}

Apply to the Form Group (Not Individual Fields!)

this.form = this.fb.group({
  password: ['', Validators.required],
  confirmPass: ['', Validators.required]
}, {
  validators: passwordsMatch  // Group-level!
});

Showing the Error

<div *ngIf="form.hasError('passwordMismatch')">
  ⚠️ Passwords don't match!
</div>

🚦 Form Valid States: The Traffic Light

Your form is like a traffic light telling you what’s happening:

graph TD A["Form States"] --> B["🔴 INVALID"] A --> C["🟢 VALID"] A --> D["🟡 PENDING"] A --> E["⚫ DISABLED"]

What Each State Means

State Meaning Example
VALID All dogs happy! Green light to submit
INVALID A dog found a problem Show error messages
PENDING Detective dog working Show loading spinner
DISABLED Gate is closed Can’t edit the field

Checking States in Code

// The whole form
if (this.form.valid) {
  this.submit();
}

// A single field
if (this.form.get('email')?.valid) {
  console.log('Email looks good!');
}

In Your Template

<button
  [disabled]="form.invalid || form.pending">
  Submit
</button>

<span *ngIf="email.invalid && email.touched">
  Please enter a valid email
</span>

👆 Form Touched States: “Did They Try?”

Touched means: “The user clicked in this field and then clicked out.”

Why does this matter? You don’t want to yell at users before they even tried!

graph LR A["Field starts UNTOUCHED"] --> B["User clicks in"] B --> C["User clicks out"] C --> D[Now it's TOUCHED!]

The States

State Meaning
touched User visited and left the field
untouched User never focused on it
dirty User changed the value
pristine Value never changed

Smart Error Display

<!-- Only show errors AFTER user tried -->
<div class="error"
  *ngIf="email.invalid && email.touched">
  Please fix your email
</div>

The Golden Rule

Show errors when:
  field.invalid && field.touched

This way, users aren't scared off
before they even start!

🔄 Form Value Changes: Listening to the Castle

Every time a visitor speaks (user types), you can hear them!

Listening to Everything

this.form.valueChanges.subscribe(values => {
  console.log('Form changed:', values);
  // { name: 'John', email: 'john@...' }
});

Listening to One Field

this.form.get('email')?.valueChanges
  .subscribe(email => {
    console.log('Email is now:', email);
  });

Real-World Use: Live Search

this.searchControl.valueChanges.pipe(
  debounceTime(300),  // Wait 300ms
  distinctUntilChanged() // Only if changed
).subscribe(term => {
  this.search(term);
});

Status Changes Too!

this.form.statusChanges.subscribe(status => {
  console.log('Form status:', status);
  // 'VALID', 'INVALID', or 'PENDING'
});

🎯 Putting It All Together

Here’s a complete castle gate (form) with all the guard dogs:

@Component({...})
export class SignupComponent {
  form = this.fb.group({
    // Built-in validators
    username: ['', [
      Validators.required,
      Validators.minLength(3)
    ], [
      this.checkUserExists()  // Async!
    ]],

    email: ['', [
      Validators.required,
      Validators.email
    ]],

    // Password group with cross-field
    passwords: this.fb.group({
      password: ['', [
        Validators.required,
        this.hasNumber  // Custom!
      ]],
      confirm: ['', Validators.required]
    }, {
      validators: this.passwordsMatch
    })
  });

  // Listen to changes
  ngOnInit() {
    this.form.valueChanges.subscribe(
      val => console.log(val)
    );
  }
}

🌟 Quick Reference Card

Concept Purpose Key Point
Built-in Validators Ready-made checks required, email, min, max
Custom Validators Your special rules Return null or {error}
Async Validators Server checks Returns Observable
Cross-field Compare fields Applied to FormGroup
Valid States Current status valid, invalid, pending
Touched States User interaction touched, dirty
Value Changes Live updates Subscribe to Observable

🎉 You Did It!

You now understand how guard dogs (validators) protect your castle (form)! Remember:

  1. Built-in dogs handle common checks
  2. Custom dogs handle special rules
  3. Detective dogs check with servers
  4. Team dogs compare multiple fields
  5. States tell you what’s happening
  6. Changes let you react in real-time

Now go build forms that are both user-friendly AND bulletproof! 🏰🐕

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.