I have a form in angular that that a Category text input and an ID input. The ID must be unique to the category. So if I have the following items for Cat1
:
Cat1 - 123
Cat1 - 245
Cat1 - 456
Then If i tried to enter a new item with the category Cat1
and the id 123
then that input wouldn't be unique to the category and the form could not be submitted. If the id changed to 1234
then it would be valid.
To achieve this I have a custom directive called unique
that required ngModel
. It looks like this-
HTML-
<input name="ID"
required
unique="id in getItemsByCategory(newCategory)"
type="text"
ng-model="newId"></input>
JS-
.directive('unique', function() {
return {
require: '^ngModel',
link: function(scope, ele, attr, ngModelController) {
ngModelController.$validators.unique = function(val) {
var uniqueInRegex = /([^\s]+)\s+in\s([^\s]+)/i;
var matches = attr.unique.match(uniqueInRegex);
var property = matches[1];
var collection = scope.$eval(matches[2]);
for(var i = 0; i < collection.length; i++) {
var item = collection[i];
if(item[property] === val) {
console.log('not unique');
return false;
}
}
console.log('unique');
return true;
};
}
};
});
Which works fine:
But if the validator finds the field is not unique based on the category, and the category field changes, then the validator doesn't reevaulate.
Here is a JSBin of what what's seen in these gifs:
http://jsbin.com/wubesutugo/edit?html,js,output
Is there anyway I can have one input "touch" another input when it changes? I want this validation directive to be generic because i have multiple places I'd like to use it. So I don't want this logic in the controller.
Your solution with the ng-change
is sufficient. An alternative would be using a watch ($watchCollection
, to be precise):
.directive('unique', function() {
var uniqueInRegex = /([^\s]+)\s+in\s([^\s]+)/i;
return {
require: '^ngModel',
link: function(scope, ele, attr, ngModelController) {
var matches = attr.unique.match(uniqueInRegex);
var property = matches[1];
var collectionExpr = matches[2];
scope.$watchCollection(collectionExpr, function(newval) {
ngModelController.$validate();
});
ngModelController.$validators.unique = function(val) {
var collection = scope.$eval(collectionExpr);
for(var i = 0; i < collection.length; i++) {
var item = collection[i];
if(item[property] === val) {
console.log('not unique');
return false;
}
}
console.log('unique');
return true;
};
}
};
})
(Also demonstrates calculating the regular expression just once.)
Try it: http://jsbin.com/wiyugozuje/1/edit?js,console,output