I've written a match-model
Angular directive that I use for password/password-repeat process when users register in my application. Password repeat field has this particular attribute that validates this field against original password field.
My directive has scope.$watch
for optimization purposes because I don't have to read related scope property value each time I validate my repeat password scope property but I rather just use cached value which changes when related scope property value changes (original password).
This is my directive:
.directive(matchModel, [$timeout, function ($timeout) {
return {
require: ngModel,
link: function (scope, element, attributes, ngModelController) {
var valueCache = null;
// watch match-model model property value
scope.$watch(attributes[matchModel], function (newValue, oldValue) {
valueCache = newValue;
/*
scope.$apply(); // error $digest in progress
$timeout(function () { scope.$digest(); }); // no error, not working
$timeout(function () { scope.$apply(); }); // no error, not working
*/
});
// add model validation parser
ngModelController.$parsers.unshift(function (value) {
ngModelController.$setValidity(match, value === valueCache);
return value === valueCache ? value : undefined;
});
}
};
}]);
My form consists of two fields (that are relevant for this question):
<input type=password name=password id=password placeholder=password
class=validate autocomplete=off
required
ng-minlength=6
ng-model=data.password />
<input type=password name=passwordRepeat id=passwordRepeat placeholder=repeat password
class=validate autocomplete=off
required
ng-model=data.passwordRepeat
match-model=data.password />
Requirements
- When user enters first password, field becomes valid when enough characters are entered - in above case that's 6 characters
- when user enters second password, field should become valid when data matches first password
- if user returns to first field and changes original password, second field should invalidate
How it currently works
1 and 2 work as expected, but 3 doesn't. That's why I wanted to add scope.$digest
to propagate scope model changes to other fields. And scope.$watch
is the right moment because it executes when that particular scope model property changes.
It seems that scope.$digest
(or scope.$apply
for that matter) doesn't validate model. Validation doesn't seem to be executed along with it.
Question
So how should I do something like scope.$validate
or even better element.$validate
so it would only validate my particular field instead of the whole model (resulting in invalid form in the UI).