I have a situation where a user needs to enter input into text areas created by ng-repeat. If the user enters a value that has already been entered both the new and existing
I think it might because the verifyDuplicate method keeps setting and re-setting the validity of the same model, so the validity of the model triggering method invocation will be based on the last comparison result in the loop.
One way to solve this is to let the verifyDuplicate method work on the persons collection as a whole, no matter which model change triggers the method invocation, in this example the $setValidity method is not used, instead, a isDuplicate property on the model is set to indicate duplication.
HTML:
<ng-form name="personForm">
<div ng-class="{ 'has-error' :
personForm.personName.$invalid }">
<input type='number'
name="personName"
ng-class="empty"
ng-model="person.name"
ng-change="verifyDuplicate()"/>
</div>
</ng-form>
<div class='error'
ng-if='person.isDuplicate'>
Duplicate.
</div>
JavaScript:
$scope.verifyDuplicate = function() {
var sorted, i;
sorted = $scope.persons.concat().sort(function (a, b) {
if (a.name > b.name) return 1;
if (a.name < b.name) return -1;
return 0;
});
for(i = 0; i < $scope.persons.length; i++) {
sorted[i].isDuplicate = ((sorted[i-1] && sorted[i-1].name == sorted[i].name) || (sorted[i+1] && sorted[i+1].name == sorted[i].name));
}
};
JSFiddler: http://jsfiddle.net/luislee818/pkhxkozp/4/
If we insist using $setValidity, I can think of connecting individual model to its form with "ng-init" directive, however this looks cumbersome and there might be better ways if we go with this approach.
HTML:
<ng-form name="personForm">
<div ng-class="{ 'has-error' :
personForm.personName.$invalid }">
<input type='number'
name="personName"
ng-init="person.form = personForm"
ng-class="empty"
ng-model="person.name"
ng-change="verifyDuplicate()"/>
</div>
</ng-form>
<div class='error'
ng-show=
'personForm.personName.$error.duplicate'>
Duplicate.
</div>
JavaScript:
$scope.verifyDuplicate = function() {
var sorted, i, isDuplicate;
sorted = $scope.persons.concat().sort(function (a, b) {
if (a.name > b.name) return 1;
if (a.name < b.name) return -1;
return 0;
});
for(i = 0; i < $scope.persons.length; i++) {
isDuplicate = ((sorted[i-1] && sorted[i-1].name == sorted[i].name) || (sorted[i+1] && sorted[i+1].name == sorted[i].name));
sorted[i].form.personName.$setValidity('duplicate',!isDuplicate);
}
};
JSFiddle: http://jsfiddle.net/luislee818/nzd87f1s/1/