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 values should be validated as false. If one of the values (existing or new) gets changed, the validation should be updated correspondingly.
I have tried quite a variety of options, currently this is what comes close, but is still not 100%.
HTML:
<body ng-app="ap" ng-controller="con">
<table>
<tr>
<td>name</td>
</tr>
<tr ng-repeat="person in persons">
<td>
<ng-form name="personForm">
<div ng-class="{ 'has-error' :
personForm.personName.$invalid }">
<input type='text'
name="personName"
ng-class="empty"
ng-model="person.name"
ng-change="verifyDuplicate(this, person)"/>
</div>
</ng-form>
</td>
</tr>
</table>
JavaScript:
var app = angular.module("ap",[]);
app.controller("con",function($scope){
$scope.persons = [
{name: 'a'},
{name: 'b'},
{name: 'c'}
];
$scope.empty = "normal";
$scope.verifyDuplicate = function(domScope, object){
for(var i = 0; i < $scope.persons.length; i++) {
if($scope.persons[i].name === object.name && $scope.persons[i] !== object) {
domScope.personForm.personName.$setValidity('duplicate',false);
}
else {
domScope.personForm.personName.$setValidity('duplicate',true);
}
}
};
});
Any help on this would be appreciated.
Here is a fiddle Fiddle of code
AngularJS Form Validation AngularJS provides client-side form validation. It checks the state of the form and input fields (input, textarea, select), and lets you notify the user about the current state. It also holds the information about whether the input fields have been touched, or modified, or not.
You can use unique filter while using ng-repeat . If you use track by $index then unique won't work.
ng-pristine : the control hasn't been interacted with yet. ng-dirty : the control has been interacted with. ng-touched : the control has been blurred. ng-untouched : the control hasn't been blurred.
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/
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