Tutorials Logic, IN info@tutorialslogic.com

Angular Form Validation Built in Custom

Angular Form Validation Built in Custom

Angular Form Validation Built in Custom is an important Angular topic because it appears in real projects, debugging sessions, and interviews. Learn the meaning first, then connect it to a small working example so the rule does not stay abstract.

For this page, focus on what problem Angular Form Validation Built in Custom solves, where developers usually make mistakes, and how to verify the result. The audit note for this lesson was: limited checklist/practice/mistake/FAQ notes .

A strong understanding of Angular Form Validation Built in Custom should include syntax, behavior, one realistic use case, one failure case, and one quick way to check your work with tools or output.

Angular Form Validation Built in Custom should be studied as a practical Angular lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.

In the angular > form-validation page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.

Form Validation Overview

Angular provides a powerful validation system for both Reactive and Template-driven forms. Validators can be built-in (required, minLength, email) or custom. Angular tracks the validity state of each control and the form as a whole, making it easy to show error messages and disable submit buttons.

Built-in Validator Description Usage
Validators.required Field must not be empty required attribute or Validators.required
Validators.minLength(n) Minimum character count minlength="3" or Validators.minLength(3)
Validators.maxLength(n) Maximum character count maxlength="50" or Validators.maxLength(50)
Validators.email Valid email format email attribute or Validators.email
Validators.pattern(regex) Must match regex pattern Validators.pattern(/^[0-9]+$/)
Validators.min(n) Minimum numeric value Validators.min(0)
Validators.max(n) Maximum numeric value Validators.max(100)

Reactive Form Validation

In reactive forms, validators are added programmatically in the component class. This gives full control over validation logic and makes it easy to test.

Reactive Form with Validation

Reactive Form with Validation
import { Component, inject } from '@angular/core';
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';

@Component({
    selector: 'app-register',
    standalone: true,
    imports: [ReactiveFormsModule],
    templateUrl: './register.component.html'
})
export class RegisterComponent {
    private fb = inject(FormBuilder);

    form = this.fb.group({
        name: ['', [Validators.required, Validators.minLength(2)]],
        email: ['', [Validators.required, Validators.email]],
        password: ['', [Validators.required, Validators.minLength(8)]],
        age: [null, [Validators.required, Validators.min(18), Validators.max(120)]]
    });

    // Convenience getters for template access
    get name()     { return this.form.get('name')!; }
    get email()    { return this.form.get('email')!; }
    get password() { return this.form.get('password')!; }
    get age()      { return this.form.get('age')!; }

    onSubmit() {
        if (this.form.valid) {
            console.log('Form submitted:', this.form.value);
        } else {
            this.form.markAllAsTouched();
        }
    }
}

Reactive Form Validation

Reactive Form Validation
<form [formGroup]="form" (ngSubmit)="onSubmit()">

    <div>
        <label>Name</label>
        <input formControlName="name" />
        @if (name.invalid && name.touched) {
            @if (name.errors?.['required']) {
                <span class="tl-text-danger">Name is required.</span>
            }
            @if (name.errors?.['minlength']) {
                <span class="tl-text-danger">Name must be at least 2 characters.</span>
            }
        }
    </div>

    <div>
        <label>Email</label>
        <input formControlName="email" type="email" />
        @if (email.invalid && email.touched) {
            @if (email.errors?.['required']) {
                <span class="tl-text-danger">Email is required.</span>
            }
            @if (email.errors?.['email']) {
                <span class="tl-text-danger">Enter a valid email address.</span>
            }
        }
    </div>

    <button type="submit" [disabled]="form.invalid">Register</button>

</form>

Custom Validators

When built-in validators are not enough, you can create custom validators. A validator is a function that takes an AbstractControl and returns either null (valid) or a ValidationErrors object (invalid).

Custom Validators

Custom Validators
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

// 1. No whitespace validator
export function noWhitespaceValidator(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
        const hasWhitespace = (control.value || '').includes(' ');
        return hasWhitespace ? { whitespace: true } : null;
    };
}

// 2. Password strength validator
export function passwordStrengthValidator(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
        const value = control.value || '';
        const hasUpper   = /[A-Z]/.test(value);
        const hasLower   = /[a-z]/.test(value);
        const hasNumber  = /[0-9]/.test(value);
        const hasSpecial = /[!@#$%^&*]/.test(value);
        const isStrong   = hasUpper && hasLower && hasNumber && hasSpecial;
        return isStrong ? null : { weakPassword: { hasUpper, hasLower, hasNumber, hasSpecial } };
    };
}

// 3. Cross-field validator - passwords must match
export function passwordMatchValidator(control: AbstractControl): ValidationErrors | null {
    const password        = control.get('password');
    const confirmPassword = control.get('confirmPassword');
    if (!password || !confirmPassword) return null;
    return password.value === confirmPassword.value ? null : { passwordMismatch: true };
}

Custom Validators

Custom Validators
import { Component, inject } from '@angular/core';
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { noWhitespaceValidator, passwordStrengthValidator, passwordMatchValidator } from './custom-validators';

@Component({
    selector: 'app-signup',
    standalone: true,
    imports: [ReactiveFormsModule],
    template: `
        <form [formGroup]="form" (ngSubmit)="onSubmit()">
            <input formControlName="username" placeholder="Username" />
            @if (form.get('username')?.errors?.['whitespace']) {
                <span class="tl-text-danger">No spaces allowed.</span>
            }

            <input formControlName="password" type="password" placeholder="Password" />
            @if (form.get('password')?.errors?.['weakPassword']) {
                <span class="tl-text-danger">Password needs uppercase, lowercase, number and special char.</span>
            }

            <input formControlName="confirmPassword" type="password" placeholder="Confirm Password" />
            @if (form.errors?.['passwordMismatch']) {
                <span class="tl-text-danger">Passwords do not match.</span>
            }

            <button type="submit" [disabled]="form.invalid">Sign Up</button>
        </form>
    `
})
export class SignupComponent {
    private fb = inject(FormBuilder);

    form = this.fb.group({
        username: ['', [Validators.required, noWhitespaceValidator()]],
        password: ['', [Validators.required, passwordStrengthValidator()]],
        confirmPassword: ['', Validators.required]
    }, { validators: passwordMatchValidator });

    onSubmit() {
        if (this.form.valid) console.log(this.form.value);
    }
}

Form Control States

Angular tracks the state of each form control. Understanding these states helps you show the right error messages at the right time.

State Property Meaning
Pristine control.pristine User has not changed the value yet
Dirty control.dirty User has changed the value
Untouched control.untouched User has not focused and left the field
Touched control.touched User has focused and left the field
Valid control.valid All validators pass
Invalid control.invalid At least one validator fails
Pending control.pending Async validator is running

Angular Form Validation Built in Custom state check

Angular Form Validation Built in Custom state check
const state = { topic: "Angular Form Validation Built in Custom", ready: true };
if (state.ready) {
  console.log(state.topic + ": render or run the normal path");
}

Angular Form Validation Built in Custom fallback check

Angular Form Validation Built in Custom fallback check
const response = null;
const message = response?.message ?? "Angular Form Validation Built in Custom: show a clear fallback";
console.log(message);
Key Takeaways
  • Explain the purpose of Angular Form Validation Built in Custom before memorizing syntax.
  • Run or trace one small Angular example and confirm the output.
  • Test one normal case, one edge case, and one mistake case for Angular Form Validation Built in Custom.
  • Write the rule in your own words after checking the example.
  • Connect Angular Form Validation Built in Custom to a real project scenario instead of treating it as an isolated definition.
Common Mistakes to Avoid
WRONG Memorizing Angular Form Validation Built in Custom without the situation where it is useful.
RIGHT Connect Angular Form Validation Built in Custom to a concrete Angular task.
Purpose makes syntax easier to recall.
WRONG Testing Angular Form Validation Built in Custom only with the perfect input.
RIGHT Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Real bugs usually appear outside the perfect path.
WRONG Changing code before reading the visible symptom or error message.
RIGHT Inspect the output, state, configuration, or stack trace connected to Angular Form Validation Built in Custom.
Evidence keeps debugging focused.
WRONG Memorizing Angular Form Validation Built in Custom without the situation where it is useful.
RIGHT Connect Angular Form Validation Built in Custom to a concrete Angular task.
Purpose makes syntax easier to recall.

Practice Tasks

  • Modify the example so it handles a different input or condition.
  • Write one mistake related to Angular Form Validation Built in Custom, then fix it and explain the fix.
  • Summarize when to use Angular Form Validation Built in Custom and when another approach is better.
  • Write a small example that uses Angular Form Validation Built in Custom in a realistic Angular scenario.
  • Change one important value in the Angular Form Validation Built in Custom example and predict the result first.

Frequently Asked Questions

The common mistake is memorizing syntax without understanding when the behavior changes or fails.

Remember the problem it solves in Angular, then attach the syntax or steps to that problem.

You can predict the result of a small example, explain a failure case, and choose it over a nearby alternative for a clear reason.

They often copy the syntax but skip the state, input, dependency, selector, route, type, or configuration that controls the behavior.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.