If your custom validation directive is not being triggered in AngularJS, it is likely due to one or more of the following reasons:
- Directive is not properly registered
- Directive is not applied correctly in the form
ng-model
is missing or incorrect- The
$setValidity
function is not being called properly - Directive is not inside a form (
ng-form
)
Let’s go step by step to debug and fix this issue.
Step 1: Ensure the Directive is Registered Correctly
The first step is to ensure your directive is properly defined and registered in your AngularJS module.
Correct Example: Custom Validation Directive for Username
1️⃣ Directive Definition (Ensure it Calls $setValidity
)
var app = angular.module("myApp", []);
app.directive("validateUsername", function () {
return {
require: "ngModel", // Ensures it works with `ng-model`
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.push(function (value) {
if (value && value.length >= 3) {
ngModel.$setValidity("usernameValid", true);
} else {
ngModel.$setValidity("usernameValid", false);
}
return value;
});
}
};
});
Why This Works?
- Uses
require: "ngModel"
to integrate with AngularJS forms. - Uses
$parsers.push()
to modify input values and check validity. - Calls
ngModel.$setValidity("usernameValid", true/false)
to enable validation.
Step 2: Apply the Directive Correctly in the Form
Now, apply the directive in a form with ng-model
to ensure it works:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AngularJS Custom Validation</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body ng-controller="myController">
<form name="userForm" novalidate>
<label>Username:</label>
<input type="text" name="username" ng-model="user.username" validate-username required>
<span class="error" ng-show="userForm.username.$error.usernameValid">
Username must be at least 3 characters long.
</span>
<br><br>
<button type="submit" ng-disabled="userForm.$invalid">Submit</button>
</form>
<script>
var app = angular.module("myApp", []);
app.controller("myController", function ($scope) {
$scope.user = {};
});
app.directive("validateUsername", function () {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.push(function (value) {
if (value && value.length >= 3) {
ngModel.$setValidity("usernameValid", true);
} else {
ngModel.$setValidity("usernameValid", false);
}
return value;
});
}
};
});
</script>
<style>
.error {
color: red;
display: block;
}
</style>
</body>
</html>
Why This Works?
- The directive (
validate-username
) is correctly added to the input field. - The form name (
userForm
) ensures AngularJS tracks validity. ng-show="userForm.username.$error.usernameValid"
displays the error message.
Step 3: Debugging the Issue
If the directive is not being called, follow these debugging steps:
1. Check if the Directive is Executing (console.log
)
Modify the directive to add debugging logs:
app.directive("validateUsername", function () {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModel) {
console.log("Directive initialized for", element[0].name);
ngModel.$parsers.push(function (value) {
console.log("Validating:", value);
if (value && value.length >= 3) {
ngModel.$setValidity("usernameValid", true);
} else {
ngModel.$setValidity("usernameValid", false);
}
return value;
});
}
};
});
🔹 Check Browser Console (F12
→ Console) for messages like:
makefileCopyEditDirective initialized for username
Validating: ab
Validating: abc
2. Ensure ng-model
is Set Correctly
Incorrect (No ng-model
)
<input type="text" validate-username>
Fix: Add ng-model
<input type="text" name="username" ng-model="user.username" validate-username>
3. Ensure $setValidity
is Called Correctly
If the form never updates validity, modify $setValidity
to debug:
ngModel.$setValidity("usernameValid", false);
console.log("Setting validity:", false);
4. Ensure novalidate
is on the <form>
Without novalidate
, HTML5 validation may override AngularJS validation:
<form name="userForm" novalidate>
Step 4: Alternative Approach Using $validators
Instead of $parsers.push()
, we can use $validators
:
app.directive("validateUsername", function () {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModel) {
ngModel.$validators.usernameValid = function (value) {
return value && value.length >= 3;
};
}
};
});
Why Use $validators
?
- Automatically triggers when
ng-model
updates. - Eliminates the need for
$parsers.push()
.
Conclusion: Fix Summary
1️⃣ Correctly Register the Directive
app.directive("validateUsername", function () {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.push(function (value) {
ngModel.$setValidity("usernameValid", value && value.length >= 3);
return value;
});
}
};
});
2️⃣ Apply the Directive Inside a Form
<form name="userForm" novalidate>
<input type="text" name="username" ng-model="user.username" validate-username required>
</form>
3️⃣ Debug Using console.log
console.log("Directive initialized for", element[0].name);
console.log("Validating:", value);
console.log("Setting validity:", true/false);
4️⃣ Ensure novalidate
on <form>
<form name="userForm" novalidate>