Custom validation directive not being called

Loading

If your custom validation directive is not being triggered in AngularJS, it is likely due to one or more of the following reasons:

  1. Directive is not properly registered
  2. Directive is not applied correctly in the form
  3. ng-model is missing or incorrect
  4. The $setValidity function is not being called properly
  5. 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>

Leave a Reply

Your email address will not be published. Required fields are marked *