Reputation: 4021
I have list of inputs from an array created via ng-repeat. I want to check if there are any duplicated values in them. If any duplicated value found it shows an error message. I found what I was wanting in this 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));
}
};
So I implemented this in my 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));
}
};
But looks like it's not working for some reason. I am using a different nested array of objects here.What I am doing wrong here ?
Thanks in advance.
Upvotes: 0
Views: 2175
Reputation: 6221
It doesn't work because you have the wrong key name in the sort function and you are trying to use a nested object.
Just modifying it to this will get it to work with the first object in the array. You would need to iterate through each object though to get it to work for all of them.
$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));
}
};
Because you are using a nested object, this becomes a slightly more complicated problem to solve. You have an array of objects that also have arrays in them. If you (can) put everything into a flatter object, it's simple.
The csTagGrp[0]
tells it to access the first object in the csTagGrp array, which is:
{
"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"
}]
}
So now sorted
accesses the csTags array in the object at [0] in the csTagGrp array and performs the sort on all the keys
in that array. So far so good. But with the object structure you have here, you need to iterate through both arrays (that is, all the objects in csTagGrp, as well as each csTags array in each csTagGrp object) and perform a sort on ALL of them. This usually involves multiple for loops.
So to accomplish this, I concat'ed all the csTags arrays (using a for loop) into a new array, preSort
, which then gets passed to sort. This gives us what we need (one flat array) to check all the csTags arrays for duplicates.
$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));
}
};
});
Upvotes: 3
Reputation: 470
Unfortunately there are quite a lot of problems, but I believe none are impossible to overcome. The biggest problem lies in the difference in data structures. In the original fiddle, the data is in a simple array:
$scope.persons = [
{name: 1},
{name: 2},
{name: 3}
];
whereas in your plunker, the data is (as you already mentioned) quite a lot more nested:
$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
}]
...so you just can't use something like this (from your 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));
}
And the problems are:
$scope.csTagGrp
is an Array of objects (that each have a csTags
property), it is not an Object with a csTags
property
$scope.csTagGrp.csTags
is undefined
-> trying to invoke concat()
on undefined
doesn't - naturally - workcsTags
property within a single object inside $scope.csTagGrp
, for example like this: sorted = $scope.csTagGrp[0].csTags.concat().sort(function(a, b) {
but then again, that would sort only the first object within $scope.csTagGrp
, and not allwhich leads us to the next problem: the original duplicate verification works, because it just sorts a flat array. With your nested array, this approach would only work within a single group, not throughout all objects in $scope.csTagGrp
$scope.csTagGrp
separately, and that's pretty much it)but if (and I suspect when) you would like to detect duplicates within each of the objects, you will need to come up with a new way to extract and sort the csTags
:
csTags
array from each objectcreate a flat array of all the csTags
arrays, i.e. looking like this:
[
{"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
]
name
) to what you have (keys
)Hopefully this helps you to move ahead!
Upvotes: 1