In AngularJS, directives are powerful tools used to create reusable components and behavior. A common use case for directives is to implement custom form validation logic. By creating a reusable validation directive, you can modularize your form validation, making it easier to apply and maintain across different parts of your application.
Objective
We will create a reusable validation directive in AngularJS that checks whether an input field contains a valid email address. This directive will be reusable, allowing it to be used with different input fields and forms across the application.
Steps to Create a Reusable Validation Directive
1. Create the Directive in AngularJS
First, we’ll define a new directive called validEmail
. This directive will use a custom validation function to check if the value in the input field is a valid email address.
2. HTML Structure for the Form
Here’s an example form where we will use the validEmail
directive for the email input field.
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="FormController">
<form name="myForm" ng-submit="submitForm()" novalidate>
<label for="email">Email:</label>
<input type="email" name="email" ng-model="email" valid-email />
<div ng-show="myForm.email.$invalid && myForm.email.$dirty">
<span>Email is invalid.</span>
</div>
<br/><br/>
<button type="submit" ng-disabled="myForm.$invalid">Submit</button>
</form>
</div>
</body>
</html>
3. Define the AngularJS Module and Controller
Now, we’ll define an AngularJS module named myApp
and a controller FormController
to handle the form submission.
angular.module('myApp', [])
.controller('FormController', function($scope) {
// Function to handle form submission
$scope.submitForm = function() {
if ($scope.myForm.$valid) {
alert("Form submitted successfully!");
} else {
alert("Please correct the form errors before submitting.");
}
};
});
4. Create the Custom Validation Directive
In the directive, we will define the custom validation for the email field using AngularJS’s $validators
. This will ensure that our custom validation logic is reusable and can be applied to multiple fields across different forms.
angular.module('myApp')
.directive('validEmail', function() {
return {
require: 'ngModel', // This directive will require the ngModel controller
link: function(scope, element, attrs, ngModel) {
// Custom email validation
ngModel.$validators.validEmail = function(value) {
if (value) {
// Basic email validation regex
var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
return emailPattern.test(value);
}
return true; // If the value is empty, validation is passed
};
}
};
});
5. Explanation of the Code
Directive Definition (validEmail
)
require: 'ngModel'
: This ensures that the directive has access to thengModel
controller of the element. ThengModel
is used to bind the value of the input field and manage the validation state.link
function: Thelink
function is where we implement the directive’s behavior. It is called when the directive is attached to an element in the DOM. This is where we define the validation logic for the email.
Custom Validation Logic (ngModel.$validators.validEmail
)
ngModel.$validators.validEmail
: We define a custom validator by adding it to the$validators
object of thengModel
. This validator will be executed whenever the value of the input field changes.- Email Validation Regex: We use a regular expression (
emailPattern
) to validate if the value entered in the input field is a valid email format. If it matches the regex, the validator returnstrue
, indicating the validation passed. Otherwise, it returnsfalse
. - Empty Field Handling: If the field is empty, we return
true
, meaning the validation passes (as we are only validating the email format when there is a value).
Validation in the Form (ng-show
)
In the HTML form, we use ng-show
to display an error message if the email field is invalid and has been touched by the user (i.e., it’s been interacted with).
6. Reusability of the Directive
This directive is reusable in multiple forms. All you need to do is use the valid-email
attribute on any input field you want to validate. Here’s another example:
<form name="myForm" ng-submit="submitForm()">
<label for="email1">Email 1:</label>
<input type="email" name="email1" ng-model="email1" valid-email />
<label for="email2">Email 2:</label>
<input type="email" name="email2" ng-model="email2" valid-email />
<button type="submit" ng-disabled="myForm.$invalid">Submit</button>
</form>
Both email1
and email2
will be validated using the same validEmail
directive.
7. Extending the Directive for More Complex Validation
You can easily extend this directive to handle more complex validation scenarios. For example, you could modify the directive to accept custom validation patterns or even allow for asynchronous validation (e.g., checking if the email is already taken).
angular.module('myApp')
.directive('validEmail', function($http) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$validators.validEmail = function(value) {
if (value) {
var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
return emailPattern.test(value);
}
return true;
};
// Example of asynchronous email validation
ngModel.$asyncValidators.emailTaken = function(modelValue, viewValue) {
var value = modelValue || viewValue;
return $http.get('/check-email', { params: { email: value } })
.then(function(response) {
if (response.data.exists) {
return $q.reject('Email is already taken');
}
return true;
});
};
}
};
});