myHotTake

Tag: Angular ValidatorFn example

  • How Do You Create Custom Validators in Angular?

    If you enjoy this explanation or find it helpful, give it a like or share it—it helps me know what resonates with you!


    I’m a guardian of a magical bridge that only allows worthy travelers to cross. The bridge has some basic rules: you must be human, over 18 years old, and carrying a glowing gem. These rules are the “default validators”—Angular already knows how to enforce them.

    But then, one day, a wise elder tells me, “Guardian, the glowing gem rule is too vague. Some gems may glow, but they’re fake! You need a new test—only real enchanted gems should be allowed.”

    I think, “Okay, I’ll make my own test!” I create a magnifying glass that I call the ‘isEnchantedGem’ test. This test looks at a gem and checks for specific sparkles only enchanted gems have. Once I build the magnifying glass, I attach it to the bridge’s gatekeeper system.

    In Angular, I’d do the same thing for a form. Forms have default validators like “required” or “minimum length,” but if I need a custom rule—like checking for enchanted gems—I write a custom validator function. This function is the magnifying glass: it looks at the input and decides if it passes my unique test.

    Here’s the code version of my enchanted gem test:

    import { AbstractControl, ValidationErrors } from '@angular/forms';
    
    export function isEnchantedGem(control: AbstractControl): ValidationErrors | null {
      const value = control.value;
      const isValid = value && value.includes('sparkles');
      return isValid ? null : { notEnchanted: true };
    }

    I give this to the gatekeeper—my form control—so every gem (user input) is inspected for enchantment.

    And just like that, I’ve tailored the bridge rules for exactly what I need. Custom validators in Angular are your magnifying glass for input. Now, whether it’s enchanted gems or any other unique check, your form can handle it with style!


    Sure, let’s dive into Part 2 and connect the story back to JavaScript and Angular with some code examples.


    Part 2: Building the Enchanted Bridge Validator in Angular

    So, remember my enchanted bridge and its magical validator? Let’s see how we bring that story to life with JavaScript in Angular.

    Here’s the deal: in Angular, custom validators are just functions that follow a specific structure. They inspect the control (input field) and return an object with error details if the validation fails. If everything’s fine, they return null.

    Creating the Custom Validator

    Let’s write a validator function for our “enchanted gem” check. The input field should contain the word sparkles to be valid:

    import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
    
    // Our "isEnchantedGem" validator function
    export function isEnchantedGem(): ValidatorFn {
      return (control: AbstractControl): ValidationErrors | null => {
        const value = control.value;
        const isValid = value && value.includes('sparkles');
        return isValid ? null : { notEnchanted: true }; // Error if invalid
      };
    }

    Here’s what’s happening:

    1. ValidatorFn: This is the type Angular uses for custom validators. It ensures our function returns either ValidationErrors or null.
    2. Error Object: If the input is invalid, we return { notEnchanted: true }. This key-value pair helps identify the specific error.
    3. Control: The control parameter represents the form input being validated.

    Using the Validator

    Now let’s attach this validator to a form field. Angular’s Reactive Forms make this simple:

    import { FormBuilder, FormGroup, Validators } from '@angular/forms';
    import { isEnchantedGem } from './custom-validators';
    
    export class EnchantedBridgeComponent {
      magicalForm: FormGroup;
    
      constructor(private fb: FormBuilder) {
        this.magicalForm = this.fb.group({
          gem: ['', [Validators.required, isEnchantedGem()]], // Attach custom validator here
        });
      }
    
      onSubmit() {
        if (this.magicalForm.valid) {
          console.log('Welcome, traveler! Your gem is enchanted.');
        } else {
          console.log('Sorry, traveler. Your gem is not valid.');
        }
      }
    }

    Here:

    • We attach isEnchantedGem() to the gem field.
    • If the field fails validation, Angular flags it, and we can display an error to the user.

    Displaying Validation Errors

    To show users why their input failed, we use Angular’s template tools:

    <form [formGroup]="magicalForm" (ngSubmit)="onSubmit()">
      <label for="gem">Gem:</label>
      <input id="gem" formControlName="gem" />
      <div *ngIf="magicalForm.get('gem')?.errors?.notEnchanted">
        This gem is not enchanted! Add some sparkles.
      </div>
      <button type="submit">Cross the Bridge</button>
    </form>

    Here, the error object { notEnchanted: true } becomes the key we check in the template.


    Key Takeaways:

    1. Custom Validators: They’re just functions that validate input and return ValidationErrors | null.
    2. Reusable Logic: Encapsulate specific checks like isEnchantedGem into validators for clean, reusable code.
    3. Error Feedback: Use Angular’s reactive forms and error objects to dynamically show users why their input is invalid.
    4. Flexibility: Custom validators allow you to tailor validation logic to unique requirements beyond the defaults like required or minLength.