检查多个输入之间的重复值并显示错误消息

时间:2015-04-17 18:45:10

标签: javascript angularjs

我有通过ng-repeat创建的数组的输入列表。我想检查它们中是否有任何重复的值。如果发现任何重复值,则显示错误消息。 我在 JS FIDDLE

中找到了我想要的东西
<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()"/>
                   </div>
                 </ng-form>
                <div class='error'
                    ng-if='person.isDuplicate'>
                    Duplicate.
                </div>
            </td>

$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));
        }
    };

所以我在 Plunker

中实现了这一点
<div ng-repeat="item in csTagGrp">
    <div ng-repeat="person in item.csTags">
      <ng-form name="personForm">
        <div ng-class="{ 'has-error' : 
                    personForm.personName.$invalid }">
          <input type='text' name="personName" ng-class="empty" ng-model="person.keys" ng-change="verifyDuplicate()" />
        </div>
      </ng-form>
      <div class='error' ng-if='person.isDuplicate'>
        Duplicate.
      </div>
    </div>
  </div>


$scope.verifyDuplicate = function() {
    var sorted, i;

    sorted = $scope.csTagGrp.csTags.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.csTagGrp.csTags.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));
    }
  };

但看起来由于某种原因它不起作用。我在这里使用不同的嵌套对象数组。我在这里做错了什么?

提前致谢。

2 个答案:

答案 0 :(得分:3)

它不起作用,因为您在sort函数中有错误的键名,并且您正在尝试使用嵌套对象。

只需修改它就可以使它与数组中的第一个对象一起使用。您需要遍历每个对象,以使其适用于所有对象。

$scope.verifyDuplicate = function() {
    var sorted, i;

    sorted = $scope.csTagGrp[0].csTags.concat().sort(function(a, b) {
      if (a.keys > b.keys) return 1;
      if (a.keys < b.keys) return -1;
      return 0;
    });
    for (i = 0; i < $scope.csTagGrp[0].csTags.length; i++) {
      sorted[i].isDuplicate = ((sorted[i - 1] && sorted[i - 1].keys == sorted[i].keys) || (sorted[i + 1] && sorted[i + 1].keys == sorted[i].keys));
    }
  };

因为您正在使用嵌套对象,所以这将成为一个稍微复杂的问题。您有一个对象数组,其中也包含数组。如果你(可以)把所有东西放到一个更平坦的物体上,那很简单。

csTagGrp[0]告诉它访问csTagGrp数组中的第一个对象,即:

{
    "csTagTitle": "Action",
    "csTags": [{
      "keys": "1",
      "tags": "Quick Win"
    }, {
      "keys": "2",
      "tags": "follow up with respondent"
    }, {
      "keys": "3",
      "tags": "process imporvement"
    }, {
      "keys": "4",
      "tags": "Large Fix"
    }, {
      "keys": "5",
      "tags": "use in presentation"
    }]
  }

所以现在sorted访问csTagGrp数组中[0]对象中的csTags数组,并对该数组中的所有keys执行排序。到现在为止还挺好。但是使用此处的对象结构,您需要遍历两个数组(即csTagGrp中的所有对象,以及每个csTagGrp对象中的每个csTags数组)并对所有数组执行排序。这通常涉及多个for循环。

为了实现这一点,我将所有csTags数组(使用for循环)连接成一个新数组preSort,然后传递给sort。这给了我们所需的(一个平面数组)来检查所有csTags数组的重复项。

  $scope.verifyDuplicate = function() {
    var preSort = [],sorted, i, c = $scope.csTagGrp;

    for(i = 0; i < c.length; i++) {
      preSort = preSort.concat(c[i].csTags);  
    }

    sorted = preSort.concat().sort(function(a, b) {
      if (a.keys > b.keys) return 1;
      if (a.keys < b.keys) return -1;
      return 0;
    });
    console.log(sorted)
    for (i = 0; i < preSort.length; i++) {
      sorted[i].isDuplicate = ((sorted[i - 1] && sorted[i - 1].keys == sorted[i].keys) || (sorted[i + 1] && sorted[i + 1].keys == sorted[i].keys));
    }
  };
});

Here is the working demo.

答案 1 :(得分:1)

不幸的是,存在很多问题,但我相信没有什么是不可能克服的。最大的问题在于数据结构的差异。在最初的小提琴中,数据是一个简单的数组:

$scope.persons = [
    {name: 1},
    {name: 2},
    {name: 3}
];

而在你的plunker中,数据(正如你已经提到的)嵌套了很多:

$scope.csTagGrp = [{
  "csTagTitle": "Action",
  "csTags": [{
    "keys": "1",
    "tags": "Quick Win"
  }, {
    "keys": "2",
    "tags": "follow up with respondent"
  }] // snipped contents for brevity
}, {
  "csTagTitle": "Topicality",
  "csTags": [{
    "keys": "6",
    "tags": "Root cause"
  }, {
    "keys": "7",
    "tags": "Symptom"
  }] // snipped contents
}, {
  // snipped rest for brevity
}]

...所以你不能使用这样的东西(来自你的plunker):

sorted = $scope.csTagGrp.csTags.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.csTagGrp.csTags.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));
}

问题是:

  • $scope.csTagGrp数组对象(每个对象都有csTags属性),它不是对象,其中{{1}属性
    • 因此,csTags$scope.csTagGrp.csTags - &gt;尝试在undefined上调用concat()不会 - 自然 - 工作
    • 您可以在undefined内的单个对象中访问csTags属性,例如:$scope.csTagGrp但是再次,这只会排序第一个sorted = $scope.csTagGrp[0].csTags.concat().sort(function(a, b) {内的对象,而不是全部
  • 引出了下一个问题:原始的重复验证有效,因为它只是对平面数组进行排序。使用嵌套数组,此方法仅适用于单个组,而不适用于$scope.csTagGrp

    中的所有对象
    • 当然这甚至可能是你想要的功能,在这种情况下你只需要进行微小的修正(在循环中进行排序和比较,分别在$scope.csTagGrp内的每个对象,这就是它)
    • 但是如果(并且我怀疑 时)你想要检测每个对象中的重复项,你需要提出一种新方法来提取和排序{{ 1}}:

      1. 从每个对象中提取$scope.csTagGrp数组
      2. 创建一个包含所有csTags数组的平面数组,即如下所示:

        csTags
      3. 排序那个平面阵列
      4. 对排序后的数组进行重复比较
  • 这让我们得到了决赛,我想最简单的问题是:你忘记将比较属性从原始(csTags)更改为你拥有的([ {"keys": "1", "tags": "Quick Win"}, {"keys": "2", "tags": "follow up with respondent"}, // and so on from the first object {"keys": "6", "tags": "Root cause"}, {"keys": "7", "tags": "Symptom"}, // and so on from the second object, and all the rest as well ]

希望这有助于您前进!