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:
- ValidatorFn: This is the type Angular uses for custom validators. It ensures our function returns either
ValidationErrors
ornull
. - Error Object: If the input is invalid, we return
{ notEnchanted: true }
. This key-value pair helps identify the specific error. - 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 thegem
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:
- Custom Validators: They’re just functions that validate input and return
ValidationErrors | null
. - Reusable Logic: Encapsulate specific checks like
isEnchantedGem
into validators for clean, reusable code. - Error Feedback: Use Angular’s reactive forms and error objects to dynamically show users why their input is invalid.
- Flexibility: Custom validators allow you to tailor validation logic to unique requirements beyond the defaults like
required
orminLength
.