Aurelia Form Validation with aurelia-validation
In this tutorial, you will learn about Aurelia Form Validation with aurelia. We cover key concepts, practical examples, and best practices to help you master this topic.
Aurelia's validation plugin provides a declarative system for defining validation rules on your models, with automatic binding to form controls and customizable error display.
What You'll Learn
- Installing and configuring aurelia-validation
- Defining validation rules with decorators
- Displaying validation errors in templates
- Creating custom validation rules
- Async validation for server-side checks
Why It Matters
Manual validation code is repetitive and error-prone. A declarative validation system keeps your rules close to your model definitions and automatically synchronizes error states with the UI.
Real-World Use
A user registration form with required fields, email format validation, password strength requirements, and async username availability checking.
Validation Flow
flowchart TD
A[User Input] --> B[Binding Engine]
B --> C[Validation Controller]
C --> D[Rule Evaluator]
D --> E{Valid?}
E -->|Yes| F[Clear Errors]
E -->|No| G[Collect Errors]
G --> H[Update Error Renderer]
H --> I[Show Messages in UI]
F --> I
style C fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Installing and Configuring
npm install aurelia-validation
Register the plugin:
import { PLATFORM } from 'aurelia-pal';
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.plugin(PLATFORM.moduleName('aurelia-validation'));
aurelia.start().then(() => aurelia.setRoot());
}
Defining Validation Rules with Decorators
Use the @ValidationRules decorator and ValidationRules fluent API:
import { ValidationRules, Validator } from 'aurelia-validation';
export class RegistrationForm {
username = '';
email = '';
password = '';
confirmPassword = '';
constructor() {
ValidationRules
.ensure('username')
.required().minLength(3).maxLength(20)
.ensure('email')
.required().email()
.ensure('password')
.required().minLength(8).matches(/^(?=.*[A-Z])(?=.*\d)/)
.ensure('confirmPassword')
.required().satisfies((value, form) => value === form.password)
.on(this);
}
}
Expected output: Each property has validation rules defined: username must be 3-20 characters, email must be valid, password must be 8+ chars with an uppercase letter and digit, and confirmPassword must match password.
Displaying Validation Errors in Templates
Use the validation-errors custom attribute and validate binding behavior:
<template>
<form submit.delegate="submitForm()">
<div class="form-group">
<label>Username</label>
<input type="text" value.bind="username & validate">
<span class="error" repeat.for="error of validationController.errors"
if.bind="error.propertyName === 'username'">
${error.message}
</span>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" value.bind="email & validate">
</div>
<button type="submit">Register</button>
</form>
</template>
Expected output: As the user types, validation errors appear live beneath each field. The & validate binding behavior triggers validation on input changes.
Using the Validation Controller
import { autoinject } from 'aurelia-framework';
import { ValidationController, ValidationControllerFactory } from 'aurelia-validation';
@autoinject
export class RegistrationForm {
controller: ValidationController;
constructor(controllerFactory: ValidationControllerFactory) {
this.controller = controllerFactory.createForCurrentScope();
}
async submitForm(): Promise<void> {
const result = await this.controller.validate();
if (result.valid) {
// Submit to server
} else {
// Show general error message
}
}
}
Expected output: Calling controller.validate() returns a ValidateResult object with a valid boolean and array of individual results.
Creating a Custom Validation Rule
import { ValidationRule } from 'aurelia-validation';
export class PhoneNumberRule implements ValidationRule {
constructor(public message: string = 'Invalid phone number format') {}
execute(value: any, form: any): boolean {
if (!value || value === '') return true; // Skip empty (use required for that)
const cleaned = value.replace(/[\s\-\(\)]/g, '');
return /^\d{10,15}$/.test(cleaned);
}
}
// Usage
ValidationRules
.ensure('phone')
.satisfiesRule(new PhoneNumberRule())
.on(this);
Expected output: The phone field validates against the custom rule. If the cleaned value is not 10-15 digits, the error message appears.
Async Validation (Server-Side Check)
import { ValidationRules } from 'aurelia-validation';
import { ApiService } from './api-service';
export class RegistrationForm {
constructor(private api: ApiService) {
ValidationRules
.ensure('username')
.required()
.satisfies(async (value) => {
const available = await this.api.checkUsername(value);
return available === true;
}, { message: 'Username is already taken' })
.on(this);
}
}
Expected output: When the username field loses focus or the value changes, the validation controller sends a request to the server. While the async check is pending, the field shows a validating state. If the username is taken, the error message appears.
Common Mistakes
Not registering the validation plugin - Using
& validatewithout registeringaurelia-validationthrows a runtime error.Forgetting to create a ValidationController - Rules alone do nothing. You must inject a
ValidationControllerFactoryand create a controller.Using
satisfieswithout a custom message - The default message "is not valid" is unhelpful. Always provide a{ message }option.Async rules blocking the UI - Async validators should be debounced and cancelled when the input changes again. Use a debounce binding behavior like
& debounce:300.Not clearing validation on reset - When you reset a form, call
controller.reset()to clear all error messages; otherwise old errors remain visible.
Practice Questions
- What binding behavior triggers validation on input changes?
- How do you create a validation controller for a component?
- What method returns a promise that resolves to a ValidateResult object?
- How do you define a custom validation rule class?
- What should you call when resetting a form to clear all validation errors?
Challenge: Build a registration form with synchronous validation for required fields, email format, and password strength, plus async validation that checks username availability against a mock API endpoint.
FAQ
Mini Project
Build a user profile editor with fields for name, email, phone, website, and bio. Add synchronous validation rules for each field (required, format, length) and a custom website URL validator. Display errors inline beneath each field and in a summary panel at the top.
What's Next
Now that you can validate forms, learn how to write automated tests for your Aurelia components and services.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro