I've created a validation directive for my form. It basically validates a fields value based on data from another field.
It works perfect :-)
My problem is that if the other field changes after the validation was executed, the validation will not run again.
var myApp = angular.module('myApp', [])
.directive('validateInteger', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
var int1val = scope.int1;
scope.int2valid = (viewValue > int1val) ? "valid" : undefined;
if (scope.int2valid == "valid") {
ctrl.$setValidity('higher', true);
return viewValue;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
});
}
};
});
jsfiddle: http://jsfiddle.net/hanspc/vCFFQ/
ng-dirty The field has been modified. ng-valid The field content is valid. ng-invalid The field content is not valid. ng-valid-key One key for each validation.
The first method is by using validation control states which include the form sate and input state. The other method is using CSS classes. Form State and Input State: The state of the form and the input fields are updated by AngularJS and these states are used to show useful messages to the user.
pristine: This property returns true if the element's contents have not been changed. dirty: This property returns true if the element's contents have been changed. untouched: This property returns true if the user has not visited the element.
To add validation to a template-driven form, you add the same validation attributes as you would with native HTML form validation. Angular uses directives to match these attributes with validator functions in the framework.
It is a really bad idea to refer explicitly to some fields in your directive. As you can see, this has a lot of drawbacks : unportability, code repetition, brittleness, …
Just make something like that :
<input type="text" ng-model="int2" validate-greater-integer="int1" />
And :
myApp.directive('validateGreaterInteger', function() {
return {
require: 'ngModel',
scope: {
otherInteger : '=validateGreaterInteger',
}
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (viewValue > scope.otherInteger) {
ctrl.$setValidity('higher', true);
return viewValue;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
}
});
You can then simply do the typical state control (see the section "Binding to form and control state" for an exemple).
Please notice that, in this case, you can also more simply use input[number] and its min
parameter.
Edit after the discussion in comments :
Well, the functions in NgModelController.$parsers
are obviously called only when the content of the model changes. What you want to do is to make validation whenever int1
or int2
change. So just do it :-) :
link: function(scope, elm, attrs, ctrl) {
scope.$watch('data', function (data) {
if (data.int2 > data.int1) {
ctrl.$setValidity('higher', true);
return data.int2;
} else {
ctrl.$setValidity('higher', false);
return undefined;
}
}, true);
Use your own validation variable (int2valid
in your Fiddle) is also very strange. Please use the typical state control, with something like form.int2.$error.higher
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With