Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs - How to check for unique inputs and if there is a duplicate mark both as invalid

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

like image 924
avn Avatar asked Sep 18 '14 09:09

avn


People also ask

What is validation in AngularJS?

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.

How do you prevent duplicates in NG repeat?

You can use unique filter while using ng-repeat . If you use track by $index then unique won't work.

What is ng untouched?

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.


1 Answers

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/

like image 68
Dapeng Li Avatar answered Oct 16 '22 16:10

Dapeng Li