Angularjs - Как проверить уникальные входы и если есть дубликат метки как недействительные

У меня есть ситуация, когда пользователю нужно вводить ввод в текстовые области, созданные ng-repeat. Если пользователь вводит значение, которое уже было введено, новые и существующие значения должны быть проверены как ложные. Если изменяется одно из значений (существующее или новое), проверка должна быть соответствующим образом обновлена.

Я попробовал множество вариантов, в настоящее время это то, что близко, но все равно не 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);
            }
        }
    };
});

Любая помощь по этому поводу будет оценена по достоинству.

Вот скрипка Скрипт кода

Ответ 1

Я думаю, это могло бы быть вызвано тем, что метод verifyDuplicate сохраняет настройку и переопределяет допустимость той же модели, поэтому действительность вызова метода запуска модели будет основана на последнем результате сравнения в цикле.

Один из способов решения этой проблемы - позволить методу verifyDuplicate работать с коллекцией лиц в целом, независимо от того, какое изменение модели инициирует вызов метода, в этом примере метод $ setValidity не используется, вместо этого свойство isDuplicate в модели чтобы указать дублирование.

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/

Если мы настаиваем на использовании $ setValidity, я могу подумать о подключении отдельной модели к ее форме с помощью директивы "ng-init", однако это выглядит громоздким, и, если мы пойдем с этим подходом, могут быть лучшие способы.

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/