Show unique items with count of duplicate occurrences in ng-repeat - angularjs

I have a below JSON:
[{"brand":"abc"},{"brand":"xyz"},{"brand":"abc"},{"brand":"abc"},{"brand":"por"},{"brand":"xyz"}]
Using ng-repeat, How can I display like -
Brand Occurances
abc (3)
xyz (2)
por (1)
i.e. brand name (number of duplicate occurrences of same brand name)?

You can create a custom function which will be returning the count from the existing array with the repeatvie values (occurances)
Along with the filter to show the unique values from the JSON:
$scope.getCount = function(i) {
var iCount = iCount || 0;
for (var j = 0; j < $scope.brands.length; j++) {
if ($scope.brands[j].brand == i) {
iCount++;
}
}
return iCount;
}
AND a filter will look like this:
app.filter('unique', function() {
return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
})
Working Plunkr

To get unique items from an array you could write a custom filter, in AngularJS filters are used to modify the data to be displayed to the user and in order to get the count of the duplicate items from an array you can write a function on the controller's scope and call it in the view.
Check the below code snippet on how to achieve it.
angular
.module('demo', [])
.controller('DefaultController', DefaultController)
.filter('unique', unique);
function DefaultController() {
var vm = this;
vm.items = [
{
"brand":"abc"
},
{
"brand":"xyz"
},
{
"brand":"abc"
},
{
"brand":"abc"
},
{
"brand":"por"
},
{
"brand":"xyz"
}
];
vm.getBrandCount = getBrandCount;
function getBrandCount(brand) {
var count = 0;
if (brand !== undefined && brand !== null && brand.length > 0) {
for (var i = 0; i < vm.items.length; i++) {
if (vm.items[i].brand === brand) {
count++;
}
}
}
return count;
}
}
function unique() {
return function(array, key) {
if (angular.isArray(array) && array.length > 0 && key !== undefined && key !== null && key.length > 0) {
var arr = [], keys = [];
for (var i = 0; i < array.length; i++) {
if (keys.indexOf(array[i][key]) === -1) {
keys.push(array[i][key]);
arr.push(array[i]);
}
}
return arr;
}
return array;
}
}
.brandcount:before {
content: '('
}
.brandcount:after {
content: ')'
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<table>
<thead>
<tr>
<th>Brand</th>
<th>Occurances</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in ctrl.items | unique: 'brand'">
<td>
<span ng-bind="item.brand"></span>
</td>
<td>
<span class="brandcount" ng-bind="ctrl.getBrandCount(item.brand)"></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>

You need to first process your data before passing to ng-repeat like this:
var app = angular.module("sa", []);
app.controller("FooController", function($scope) {
var data = [{
"brand": "abc"
}, {
"brand": "xyz"
}, {
"brand": "abc"
}, {
"brand": "abc"
}, {
"brand": "por"
}, {
"brand": "xyz"
}];
$scope.processedData = [];
// Group the raw data based on the brand name and store the count
function groupData() {
angular.forEach(data, function(item) {
// Check https://github.com/sagrawal14/angular-extras/blob/master/src/extras/array.js for this utility "find" method
var existingBrand = $scope.processedData.find("brand", item.brand);
if (!existingBrand) {
existingBrand = item;
existingBrand.count = 0;
$scope.processedData.push(existingBrand);
}
existingBrand.count++;
});
}
groupData();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://rawgit.com/sagrawal14/angular-extras/master/src/extras/array.js"></script>
<div ng-app="sa" ng-controller="FooController">
<table>
<tr ng-repeat="data in processedData">
<td>{{data.brand}}</td>
<td>{{data.count}}</td>
</tr>
</table>
<br><br>Processed/grouped data: {{processedData | json}}
</div>

Related

how to calculate the sum of amount for same names in ng-repeat using angularjs

here is app.js
AllServices.teamAllDataFunction1(User)
.then(function(response) {
$scope.User.data=response.data['DeatilTeam'];
console.log($scope.User.data);
var sum = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
sum += parseInt($scope.User.data[i].dp_inst_pending) || 0;
}
});
here m getting all data in which so many records having same name but differnt pending amount, so i want to show only single name and the summation of there penging amount, so that i can show it in single row. I'm not getting how to achieve it.. please help me..
here is html,
<table ng-table>
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in User.data" ng-if="data.dp_inst_pending && data.dp_inst_pending == 0">
<td>{{data.AdvisorName}}</td>
<td>{{data.dp_inst_pending}}</td>
</tr>
</table>
in this way i 'm getting data
code has few generic issues, let's resolve that first.
First of all, assuming your data.dp_inst_pending is Integer, you have used it directly in ng-if. In that case, if someone actually has zero pending amount it won't be displayed.
Secondly, you want to calculate sum of pending amount for those accounts which have same name. for that you will have to run a double for loop. One to check names and other to add pending amount if name is same. I have created one sample for the same, which i think satisfies your requirements. Please go through it and optimize as required.
var myApp = angular.module("myApp", []);
myApp.controller("MyController", ['$scope',
function($scope) {
$scope.User = {};
$scope.User.data = [{
"advisor_name": "Test1",
"dp_inst_pending": 300
}, {
"advisor_name": "Test2",
"dp_inst_pending": 0
}, {
"advisor_name": "Test1",
"dp_inst_pending": 500
}, {
"advisor_name": "Test2",
"dp_inst_pending": 600
}, {
"advisor_name": "Test1",
"dp_inst_pending": 15
}, {
"advisor_name": "Test2",
"dp_inst_pending": 150
}, {
"advisor_name": "Test3",
"dp_inst_pending": 30
}];
$scope.User.summedData = [];
var sums = [];
var advisorNames = [];
for (i = 0; i < $scope.User.data.length; i++) {
var key = $scope.User.data[i].advisor_name;
if (advisorNames.indexOf(key) >= 0) {} else {
var sumOfKey = 0;
for (j = 0; j < $scope.User.data.length; j++) {
if ($scope.User.data[j].advisor_name == key) {
sumOfKey += $scope.User.data[j].dp_inst_pending;
}
}
sums.push(sumOfKey);
advisorNames.push(key);
}
}
$scope.Test = {};
$scope.Test.data = [];
for (k = 0; k < sums.length; k++) {
$scope.Test.data[k] = {
"advisor_name": advisorNames[k],
"dp_inst_pending": sums[k]
}
}
console.log(sums);
console.log(advisorNames);
console.log($scope.Test.data);
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController">
<table ng-table>
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in Test.data">
<td>{{data.advisor_name}}</td>
<td>{{data.dp_inst_pending}}</td>
</tr>
</table>
</div>
</div>
I am not optimizing it, as it should be done by you.

The ng-repeat array is updating table data for the first time i'm selecting value, but its not updating the table data only once

I'm trying to update the table view depending on select option. The table view is updating only once, when i select the option second time the view is not updating, I'm not getting what's the problem. please help me solve this..
here is app.js
$scope.User = {};
$scope.arr = [];
$scope.loaddata = function(User) {
$scope.User.site = layouts;
AllServices.teamAllDataFunction1(User)
.then(function(response) {
$scope.User.data=response.data;
});
};
$scope.getdatalayoutwise = function(User) {
var total = 0;
var total1 = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
if($scope.User.data[i].Layout == $scope.User.selectedSite) {
total += parseInt($scope.User.data[i].dp_inst_pending);
$scope.arr.push($scope.User.data[i]);
}
}
for (var j = 0; j < ($scope.User.data1).length; j++) {
if($scope.User.data1[j].Layout == $scope.User.selectedSite) {
total1 += parseInt($scope.User.data1[j].DP_Inst_Pending);
}
}
$scope.User.teamTotal = total;
$scope.User.personalTotal = total1;
$scope.data = [$scope.User.teamTotal, $scope.User.personalTotal];
$scope.totamnt = parseInt($scope.User.personalTotal) + parseInt($scope.User.teamTotal);
$scope.User.totalamount = $filter('translate')('totalpending') + ": " + $filter('currency')($scope.totamnt, "");
$scope.User.data = $scope.arr;
};
here is html
<select name="site" ng-model="User.selectedSite" ng-change="getdatalayoutwise(User)">
<option value="">--{{'selectsite_message' | translate}}--</option>
<option ng-repeat= "option in User.site" value="{{option.Layout}}">{{option.Layout}}</option>
</select>
<table ng-table>
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in User.data | filter : {Layout: User.selectedSite}: true" ng-if="data.dp_inst_pending">
<td class="ui-helper-center"><a ng-click="advisorDetails($index, data, User)">{{data.AdvisorName}}</a></td>
<td>{{data.dp_inst_pending | currency:"₹":0}}</td>
</tr>
</table>
you need to use $scope.$apply() :
$scope.getdatalayoutwise = function(User) {
$scope.$apply(function () {
var total = 0;
var total1 = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
if($scope.User.data[i].Layout == $scope.User.selectedSite) {
total += parseInt($scope.User.data[i].dp_inst_pending);
$scope.arr.push($scope.User.data[i]);
}
}
...
});
}
https://www.grafikart.fr/formations/angularjs/apply-watch-digest
Change your function to this
$scope.loaddata = function(User) {
$scope.User.data = [];
$scope.User.site = layouts;
AllServices.teamAllDataFunction1(User)
.then(function(response) {
$scope.User.data=response.data;
});
and add a ng-if
<table ng-table ng-if="User.data.length">
<tr>
<th>advisor_name</th>
<th>totalpending</th>
</tr>
<tr ng-repeat="data in User.data | filter : {Layout: User.selectedSite}: true" ng-if="data.dp_inst_pending">
<td class="ui-helper-center"><a ng-click="advisorDetails($index, data, User)">{{data.AdvisorName}}</a></td>
<td>{{data.dp_inst_pending | currency:"₹":0}}</td>
</tr>
</table>
Add this as the first line in getdatalayoutwise () function:
$scope.arr = [];
got it working by just doing following
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.getdatalayoutwise = function(User) {
var total = 0;
var total1 = 0;
for (var i = 0; i < ($scope.User.data).length; i++) {
if($scope.User.data[i].Layout == $scope.User.selectedSite) {
total += parseInt($scope.User.data[i].dp_inst_pending);
$scope.arr.push($scope.User.data[i]);
}
}
...
$scope.safeApply (function () {
$scope.User.data = $scope.arr;
});
};

Angular filter multiple columns with an array of filters

I am trying to be able to filter multiple columns on multiple values. So far I can filter multiple columns on 1 single value:
myApp.controller('MyCtrl', ['$scope', '$http', function($scope, $http) {
$scope.empList = [];
$http.get('getAllOnline.php')
.success(function(data) {
$scope.empList = data;
});
$scope.column1List = [];
$http.get('getAllSomething.php', {
params: {
wuk: "column1"
}
})
.success(function(data) {
$scope.column1 = data;
});
$scope.column2List = [];
$http.get('getAllSomething.php', {
params: {
wuk: "column2"
}
})
.success(function(data) {
$scope.column2 = data;
});
$scope.column3List = [];
$http.get('getAllSomething.php', {
params: {
wuk: "column3"
}
})
.success(function(data) {
$scope.column3 = data;
});
$scope.setColumn1Value = function(val) {
if ($scope.zelectedColumn1 == val) {
$scope.zelectedColumn1 = undefined;
} else {
$scope.zelectedColumn1 = val;
}
}
$scope.setColumn2Value = function(val) {
if ($scope.zelectedColumn2 == val) {
$scope.zelectedColumn2 = undefined;
} else {
$scope.zelectedColumn2 = val;
}
}
$scope.setColumn3Value = function(val) {
if ($scope.zelectedColumn3 == val) {
$scope.zelectedColumn3 = undefined;
} else {
$scope.zelectedColumn3 = val;
}
}
Then i use this to set my single value filters:
<ul id="Column1" class="collapse">
<li ng-repeat="emp in empList | unique:'Column1'">
<a ng-click="setColumn1Value(emp.Column1);" ng-class="{selected: emp.Column1 === zelectedColumn1}">
<div ng-repeat="someone in Column1List | filter:{Column1_id:emp.Column1}">
{{someone.value}}
</div>
</a>
</li>
</ul>
This works perfect! But now I want to be able to filter on multiple values in 1 column. So I changed my setter functions to:
$scope.zelectedColumn1=[];
$scope.setColumn1Value = function(val) {
var found = jQuery.inArray(val, $scope.zelectedColumn1);
if (found >= 0) {
// Element was found, remove it.
$scope.zelectedColumn1.splice(found, 1);
} else {
// Element was not found, add it.
$scope.zelectedColumn1.push(val);
}
console.log($scope.zelectedColumn1);
}
So now I add or remove indexes to an array instead of storing a single value. This also works, but how do I filter my columns on the contents of an array instead of on a single value as I do now:
<div class='row'>
<div class='col-lg-2 col-md-3 col-sm-6' ng-repeat="emp in empList | filter:{column1:zelectedColumn1,column2:zelectedColumn2,column3:zelectedColumn3} as res">
{{emp.column1}}
{{emp.column2}} <br>
{{emp.column3}} <br>
</div>
</div>
I have been struggling with this al day and hope someone can help me out here!

How pass the selected ID from kendo combo box to angular function

I am using a table and table body is in ng-repeat. I want to pass the ID of selected item through kendo combo box but it always pass the last item ID to the function.
<tbody>
<tr ng-repeat="hours in GetHours">
<td style="width:2%"><input type="checkbox" ng-model="hours.Selected" ng-change="RefreshSelectedDealsCount()" /></td>
<td style="width:25%;text-align:left">{{hours.ContactName}}</td>
<td style="width:25%;text-align:left">{{hours.Hours}}</td>
<td style="width:20%;text-align:left"><select id="combobox" kendo-combo-box class="form-control" k-ng-model="hours.DealName"
ng-click="GetDeals(hours)" k-options="myDealList" style="width: 190px" k-placeholder="'Select deal'"></select></td>
</tr>
</tbody>
//In JS controller->
//Get All the Deals Related to contacts
$scope.GetDeals = function (hours)
{
$scope.CurrentHour = hours;
}
// For Kendo Combo box in JS Controller
$scope.DealDataSource = {
serverFiltering: true,
transport: {
read: {
dataType: "json",
url: '/Project/GetContactDeals',
data: {
id: function () {
return $scope.CurrentHour.FKContactID;
},
},
}
}
};
$scope.myDealList = {
dataSource: $scope.DealDataSource,
dataTextField: "Todeal",
delay: 300,
autoBind:false,
highlightFirst: true,
select: function (ev) {
$scope.DelID = 0;
var dealID = this.dataItem(ev.item.index()).Dealid;
$scope.DelID = dealID;
$scope.CurrentHour.DealID = dealID
},
}
You can try with this code i think it is help you
<td style="width:20%;text-align:left"><select kendo-combo-box k-data-text-field="'Subject'" k-data-value-field="'DealID'" k-ng-model="hoursSelectedDeal" k-on-change="getSelectedContact(hoursSelectedDeal,kendoEvent)" k-data-source="hours.DealList" style="width: 190px" k-placeholder="'Select deal'"></select></td>
$scope.getSelectedContact = function (item,e) {
console.log(e.sender.$angular_scope.this.hours);
for (var i = 0; i < $scope.GetHours.length; i++) {
for (var j = 0; j < $scope.GetHours[i].DealList.length; j++) {
if ($scope.GetHours[i].DealList[j].DealID == item) {
$scope.selectedRow.DealID = $scope.GetHours[i].DealList[j].DealID;
$scope.selectedRow.DealName = $scope.GetHours[i].DealList[j].Subject;
$scope.selectedRow.ContactID = $scope.GetHours[i].FKContactID;
}
else
{
$scope.selectedRow.DealID = 0;
$scope.selectedRow.DealName = e.sender.$angular_scope.hoursSelectedDeal;
$scope.selectedRow.ContactID = e.sender.$angular_scope.this.hours.FKContactID;
}
}
}
var index = -1;
for (var k = 0; k < $scope.AllSelectedContacts.length; k++) {
if ($scope.AllSelectedContacts[k].ContactID == $scope.selectedRow.ContactID) {
if( $scope.AllSelectedContacts[k].DealID == $scope.selectedRow.DealID)
{
index = 1;
$scope.AllSelectedContacts.splice(k);
}
else
{
index = 1;
$scope.AllSelectedContacts[k].DealID = $scope.selectedRow.DealID;
$scope.AllSelectedContacts[k].DealName = $scope.selectedRow.DealName;
}
}
}
if (index == -1) {
$scope.AllSelectedContacts.push({
DealID: $scope.selectedRow.DealID,
DealName: $scope.selectedRow.DealName,
ContactID: $scope.selectedRow.ContactID
});
}
console.log($scope.selectedRow);
}

How to make ng-repeat filter out duplicate results

I'm running a simple ng-repeat over a JSON file and want to get category names. There are about 100 objects, each belonging to a category - but there are only about 6 categories.
My current code is this:
<select ng-model="orderProp" >
<option ng-repeat="place in places" value="{{place.category}}">{{place.category}}</option>
</select>
The output is 100 different options, mostly duplicates. How do I use Angular to check whether a {{place.category}} already exists, and not create an option if it's already there?
edit: In my javascript, $scope.places = JSON data, just to clarify
You could use the unique filter from AngularUI (source code available here: AngularUI unique filter) and use it directly in the ng-options (or ng-repeat).
<select ng-model="orderProp" ng-options="place.category for place in places | unique:'category'">
<option value="0">Default</option>
// unique options from the categories
</select>
Or you can write your own filter using lodash.
app.filter('unique', function() {
return function (arr, field) {
return _.uniq(arr, function(a) { return a[field]; });
};
});
You can use 'unique'(aliases: uniq) filter in angular.filter module
usage: colection | uniq: 'property'
you can also filter by nested properties: colection | uniq: 'property.nested_property'
What you can do, is something like that..
function MainController ($scope) {
$scope.orders = [
{ id:1, customer: { name: 'foo', id: 10 } },
{ id:2, customer: { name: 'bar', id: 20 } },
{ id:3, customer: { name: 'foo', id: 10 } },
{ id:4, customer: { name: 'bar', id: 20 } },
{ id:5, customer: { name: 'baz', id: 30 } },
];
}
HTML: We filter by customer id, i.e remove duplicate customers
<th>Customer list: </th>
<tr ng-repeat="order in orders | unique: 'customer.id'" >
<td> {{ order.customer.name }} , {{ order.customer.id }} </td>
</tr>
result
Customer list:
foo 10
bar 20
baz 30
this code works for me.
app.filter('unique', function() {
return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
})
and then
var colors=$filter('unique')(items,"color");
If you want to list categories, I think you should explicitly state your
intention in the view.
<select ng-model="orderProp" >
<option ng-repeat="category in categories"
value="{{category}}">
{{category}}
</option>
</select>
in the controller:
$scope.categories = $scope.places.reduce(function(sum, place) {
if (sum.indexOf( place.category ) < 0) sum.push( place.category );
return sum;
}, []);
Here's a straightforward and generic example.
The filter:
sampleApp.filter('unique', function() {
// Take in the collection and which field
// should be unique
// We assume an array of objects here
// NOTE: We are skipping any object which
// contains a duplicated value for that
// particular key. Make sure this is what
// you want!
return function (arr, targetField) {
var values = [],
i,
unique,
l = arr.length,
results = [],
obj;
// Iterate over all objects in the array
// and collect all unique values
for( i = 0; i < arr.length; i++ ) {
obj = arr[i];
// check for uniqueness
unique = true;
for( v = 0; v < values.length; v++ ){
if( obj[targetField] == values[v] ){
unique = false;
}
}
// If this is indeed unique, add its
// value to our values and push
// it onto the returned array
if( unique ){
values.push( obj[targetField] );
results.push( obj );
}
}
return results;
};
})
The markup:
<div ng-repeat = "item in items | unique:'name'">
{{ item.name }}
</div>
<script src="your/filters.js"></script>
I decided to extend #thethakuri's answer to allow any depth for the unique member. Here's the code. This is for those who don't want to include the entire AngularUI module just for this functionality. If you're already using AngularUI, ignore this answer:
app.filter('unique', function() {
return function(collection, primaryKey) { //no need for secondary key
var output = [],
keys = [];
var splitKeys = primaryKey.split('.'); //split by period
angular.forEach(collection, function(item) {
var key = {};
angular.copy(item, key);
for(var i=0; i<splitKeys.length; i++){
key = key[splitKeys[i]]; //the beauty of loosely typed js :)
}
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
Example
<div ng-repeat="item in items | unique : 'subitem.subitem.subitem.value'"></div>
I had an array of strings, not objects and i used this approach:
ng-repeat="name in names | unique"
with this filter:
angular.module('app').filter('unique', unique);
function unique(){
return function(arry){
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
};
if(arry === undefined || arry.length === 0){
return '';
}
else {
return arry.getUnique();
}
};
}
UPDATE
I was recomending the use of Set but sorry this doesn't work for ng-repeat, nor Map since ng-repeat only works with array. So ignore this answer. anyways if you need to filter out duplicates one way is as other has said using angular filters, here is the link for it to the getting started section.
Old answer
Yo can use the ECMAScript 2015 (ES6) standard Set Data structure, instead of an Array Data Structure this way you filter repeated values when adding to the Set. (Remember sets don't allow repeated values). Really easy to use:
var mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add("some text");
var o = {a: 1, b: 2};
mySet.add(o);
mySet.has(1); // true
mySet.has(3); // false, 3 has not been added to the set
mySet.has(5); // true
mySet.has(Math.sqrt(25)); // true
mySet.has("Some Text".toLowerCase()); // true
mySet.has(o); // true
mySet.size; // 4
mySet.delete(5); // removes 5 from the set
mySet.has(5); // false, 5 has been removed
mySet.size; // 3, we just removed one value
It seems everybody is throwing their own version of the unique filter into the ring, so I'll do the same. Critique is very welcome.
angular.module('myFilters', [])
.filter('unique', function () {
return function (items, attr) {
var seen = {};
return items.filter(function (item) {
return (angular.isUndefined(attr) || !item.hasOwnProperty(attr))
? true
: seen[item[attr]] = !seen[item[attr]];
});
};
});
Here's a template-only way to do it (it's not maintaining the order, though). Plus, the result will be ordered as well, which is useful in most cases:
<select ng-model="orderProp" >
<option ng-repeat="place in places | orderBy:'category' as sortedPlaces" data-ng-if="sortedPlaces[$index-1].category != place.category" value="{{place.category}}">
{{place.category}}
</option>
</select>
None of the above filters fixed my issue so I had to copy the filter from official github doc. And then use it as explained in the above answers
angular.module('yourAppNameHere').filter('unique', function () {
return function (items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
If you want to get unique data based on the nested key:
app.filter('unique', function() {
return function(collection, primaryKey, secondaryKey) { //optional secondary key
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key;
secondaryKey === undefined ? key = item[primaryKey] : key = item[primaryKey][secondaryKey];
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
Call it like this :
<div ng-repeat="notify in notifications | unique: 'firstlevel':'secondlevel'">
Add this filter:
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;
};
});
Update your markup:
<select ng-model="orderProp" >
<option ng-repeat="place in places | unique" value="{{place.category}}">{{place.category}}</option>
</select>
This might be overkill, but it works for me.
Array.prototype.contains = function (item, prop) {
var arr = this.valueOf();
if (prop == undefined || prop == null) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item) {
return true;
}
}
}
else {
for (var i = 0; i < arr.length; i++) {
if (arr[i][prop] == item) return true;
}
}
return false;
}
Array.prototype.distinct = function (prop) {
var arr = this.valueOf();
var ret = [];
for (var i = 0; i < arr.length; i++) {
if (!ret.contains(arr[i][prop], prop)) {
ret.push(arr[i]);
}
}
arr = [];
arr = ret;
return arr;
}
The distinct function depends on the contains function defined above. It can be called as array.distinct(prop); where prop is the property you want to be distinct.
So you could just say $scope.places.distinct("category");
Create your own array.
<select name="cmpPro" ng-model="test3.Product" ng-options="q for q in productArray track by q">
<option value="" >Plans</option>
</select>
productArray =[];
angular.forEach($scope.leadDetail, function(value,key){
var index = $scope.productArray.indexOf(value.Product);
if(index === -1)
{
$scope.productArray.push(value.Product);
}
});

Resources