I have one dictionary which is stored in field_detail
{{field.displayName}}
Create your own function:
productArray =[];
angular.forEach($scope.leadDetail, function(value,key){
var index = $scope.productArray.indexOf(value.Product);
if(index === -1)
{
$scope.productArray.push(value.Product);
}
});
I get a ticket saying when the user clicks save they get an error saying Unique Constraint violation, blah blah.. They want my screen to show them duplicates before the database enforces the constraint. So I wrote a function to loop through all instances of the array of objects and count the instances of it.
$scope.anyDuplicates = function () {
var dupes = false;
for (var i = 0; i < $scope.kpiList.length; i++) {
$scope.kpiList[i].cnt = 0;
for (var j = 0; j < $scope.kpiList.length; j++) {
if ($scope.kpiList[i].description == $scope.kpiList[j].description) {
$scope.kpiList[i].cnt++;
}
if ($scope.kpiList[i].cnt > 1) dupes = true;
}
}
return dupes;
}
...and I use this function in my script to prevent the save, like this:
if ($scope.anyDuplicates()) {
alert('Duplicates Detected. Please remove the duplicates before pressing the save button.');
} else {
save();
}
...and to show the user as soon as they add a new record, like this:
$scope.kpiList.push({kpiId: newId, description: newDescription, new: true});
$scope.anyDuplicates();
... and then in my HTML I have something to tell the user where the duplicate is...
<tr ng-repeat="row in kpiList | filter:searchText | orderBy:['kpiTypeId', 'description'] ">
<td>
<span
ng-show="row.cnt > 1"
style="color: red; font-size: xx-small">
duplicate
</span>
</td>
...
</tr>
Yes, I'm intentionally comparing each instance to itself. There's less code that way. I check to see if .cnt > 1 instead of > 0.
Also to take note of... the kpiList.cnt field doesn't exist until the function runs for the first time. The ng-show="row.cnt > 1" will indicate a false (not truthy) and will not display until row.cnt has a value.
Also, you should use a StyleSheet to format your span instead of putting it in the style attribute.
To piggyback off of Ben Lesh, I added the option to remove duplicate objects in an array if the keyname is falsy:
app.filter('unique', function () {
return function ( collection, keyname) {
var output = [],
keys = []
found = [];
if (!keyname) {
angular.forEach(collection, function (row) {
var is_found = false;
angular.forEach(found, function (foundRow) {
if (foundRow == row) {
is_found = true;
}
});
if (is_found) { return; }
found.push(row);
output.push(row);
});
}
else {
angular.forEach(collection, function (row) {
var item = row[keyname];
if (item === null || item === undefined) return;
if (keys.indexOf(item) === -1) {
keys.push(item);
output.push(row);
}
});
}
return output;
};
});
I worked up a JSFiddle based on the answer provided by Ben Leash:
http://jsfiddle.net/ThunderHemlock/bvsvzrr5/1/
Thanks, Ben. Other answers required the use of AngularJS UI or other such additional frameworks.
var app = angular.module('app', []);
app.filter('unique', function() {
return function(collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key = item[keyname];
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
app.controller('MyCtrl', function ($scope) {
$scope.items = [
{
id : 1,
column : "col1",
comment : "col1-label1",
text1 : "col1-label1-text1",
checked: false,
},
{
id : 2,
column : "col1",
comment : "col1-label2",
text1 : "col1-label2-text1",
checked: false,
},
{
id : 3,
column : "col2",
comment : "col2-label1",
text1 : "col2-label1-text1",
checked: false,
},
{
id : 4,
column : "col2",
comment : "col2-label2",
text1 : "col2-label2-text1",
checked: false,
},
{
id : 5,
column : "col3",
comment : "col3-label1",
text1 : "col3-label1-text1",
checked: false,
},
{
id : 6,
column : "col3",
comment : "col3-label2",
text1 : "col3-label2-text1",
checked: false,
},
{
id : 7,
column : "col4",
comment : "col4-label1",
text1 : "col4-label1-text1",
checked: false,
},
{
id : 8,
column : "col4",
comment : "col4-label2",
text1 : "col4-label2-text1",
checked: false,
}
];
});
<div ng-app="app">
<div ng-controller="MyCtrl as item">
<ul>
<li ng-repeat="item in items | unique: 'column'">
{{ item.column }}
</li>
</ul>
</div>
</div>
Just create a filter that gets the unique values, probably by a key. Something like this ought to do (I didn't test this at all, so I'll leave that business to you, this is just to give you an idea):
app.filter('unique', function() {
return function(collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key = item[keyname];
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
<div ng-repeat="item in items | unique: 'id'"></div>
Note: Array.indexOf() does not work in IE8, so if you're supporting IE8, you'll need to stub in indexOf(), or you'll need to use a slightly different approach.
Other thoughts: It's probably better just to create a filter that leverages the unique function in lowdash or underscore if you're already referencing those libraries.