Custom Validation in AngularJS
Key Concepts
- Custom Validation Functions
- Form and Input States
- Validation Directives
- Error Messages
- Form Submission Handling
- Cross-Field Validation
- Asynchronous Validation
- Custom Validators in Controllers
- Testing Custom Validators
1. Custom Validation Functions
Custom validation functions allow you to define specific rules for validating form inputs. These functions can be attached to form controls and are executed when the form is submitted or when the control value changes.
Example:
app.directive('customValidator', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$validators.customValidator = function(modelValue, viewValue) { return viewValue === 'valid'; }; } }; });
Imagine custom validation functions as security checks at an airport. Each check (function) ensures that only valid passengers (inputs) are allowed to board the plane (form submission).
2. Form and Input States
AngularJS provides various states for forms and inputs, such as $valid
, $invalid
, $pristine
, and $dirty
. These states help in tracking the validity and interaction status of form controls.
Example:
<form name="myForm"> <input type="text" name="myInput" ng-model="myInput" custom-validator> <p ng-show="myForm.myInput.$invalid">Input is invalid!</p> </form>
Think of form and input states as traffic lights. The lights (states) indicate whether the road (form) is safe to proceed (valid) or if there is an issue (invalid) that needs attention.
3. Validation Directives
Validation directives are custom directives that can be used to apply validation rules to form controls. These directives can be reused across different forms and inputs.
Example:
app.directive('minLength', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$validators.minLength = function(modelValue, viewValue) { return viewValue.length >= 5; }; } }; });
Consider validation directives as reusable tools in a toolbox. Each tool (directive) can be used to perform a specific task (validation) on different projects (forms).
4. Error Messages
Error messages are used to inform users about validation errors. These messages can be displayed conditionally based on the state of the form controls.
Example:
<form name="myForm"> <input type="text" name="myInput" ng-model="myInput" custom-validator> <p ng-show="myForm.myInput.$error.customValidator">Input must be 'valid'.</p> </form>
Imagine error messages as signs on a road. Each sign (message) points out a specific issue (error) that needs to be addressed before proceeding.
5. Form Submission Handling
Form submission handling involves controlling what happens when a form is submitted. This can include preventing submission if the form is invalid or performing additional actions before submission.
Example:
<form name="myForm" ng-submit="submitForm()"> <input type="text" name="myInput" ng-model="myInput" custom-validator> <button type="submit" ng-disabled="myForm.$invalid">Submit</button> </form>
Think of form submission handling as a gatekeeper. The gatekeeper (handler) ensures that only valid forms (passengers) are allowed to pass through (submit).
6. Cross-Field Validation
Cross-field validation involves validating one input based on the value of another input. This is useful for scenarios like password confirmation or date range validation.
Example:
app.directive('passwordMatch', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$validators.passwordMatch = function(modelValue, viewValue) { return viewValue === scope.myForm.password.$viewValue; }; } }; });
Consider cross-field validation as a puzzle. Each piece (input) must fit together (match) with another piece to complete the puzzle (form).
7. Asynchronous Validation
Asynchronous validation involves validating inputs by making asynchronous calls, such as checking if a username is available. This type of validation requires handling promises or callbacks.
Example:
app.directive('uniqueUsername', function($http) { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { return $http.get('/api/checkUsername/' + viewValue); }; } }; });
Imagine asynchronous validation as a background check. The check (validation) takes some time to complete, but once done, it provides crucial information (validity) about the input.
8. Custom Validators in Controllers
Custom validators can also be defined in controllers and used to validate form inputs. This approach is useful for complex validation logic that doesn't fit well within directives.
Example:
app.controller('MyController', function($scope) { $scope.validateInput = function(input) { return input === 'valid'; }; });
Think of custom validators in controllers as specialized tools in a workshop. Each tool (validator) is designed to handle specific tasks (validation) that require detailed attention.
9. Testing Custom Validators
Testing custom validators ensures that they work as expected. This involves writing unit tests to verify the behavior of the validators under different conditions.
Example:
describe('customValidator', function() { var $compile, $rootScope; beforeEach(module('myApp')); beforeEach(inject(function(_$compile_, _$rootScope_) { $compile = _$compile_; $rootScope = _$rootScope_; })); it('should validate input correctly', function() { var element = $compile('<form name="myForm"><input name="myInput" ng-model="myInput" custom-validator></form>')($rootScope); $rootScope.myInput = 'valid'; $rootScope.$digest(); expect($rootScope.myForm.myInput.$valid).toBe(true); }); });
Consider testing custom validators as quality control in a factory. Each product (validator) is rigorously tested (unit tested) to ensure it meets the required standards (expected behavior).