how to prevent duplicate in array push in angularjs - arrays

my code is like this :
var arr = [];
arr.push(item1,item2);
so arr will contain like:
["name","thing1"]
But i got problem when pushing element with same exact value, how do i filter same element value but still accepting update/changes. JSFIDDLE

You can use arr.indexOf which returns -1 if it is not found, so you can add it then.
e.g.
if (arr.indexOf(item) == -1) {
arr.push(item);
}
However, this does not work in old browsers...
JQuery has a method ($.indexOf) that works in every browser, even very old ones.

Just javascript is enough.
If an array contains the item its index is >= 0
so you can do this, if index == -1 , item does not exist in the array, so you can push unique item
if(arr.indexOf(item) == -1) {
arr.push(item);
}
Edit:
You asked for changing the number, this is how
var index = arr.indexOf(item);
if(index > -1) { //checking if item exist in array
arr[index]++; // you can access that element by using arr[index],
// then change it as you want, I'm just incrementing in above example
}

As what most of the answers have pointed out, you can use the Array.prototype.indexOf() method to determine if a value exists or not. In order to check for this, check the array of strings against your ng-models value property, selects.value, within the ng-change() event callback.
DEMO
Javascript
$scope.goChange = function(name, value){
if(!~arr.indexOf(value)) {
arr.push(name, value);
console.log(arr);
}
};
HTML
<select ng-model="selects" ng-change="goChange(item.name, selects.value)" ng-options="i as i.value for i in options">
<option value=""></option>
</select>

You should use Angular Filters.
Some implementations can be found as answers to a similar question: How to make ng-repeat filter out duplicate results

To filter duplicates in an array (es6):
let arr = ['foo', 'foo', 'bar', 'baz'];
Array.from(new Set(arr));
console.log(arr);
// ['foo', 'bar', 'baz'];

Related

What is the criteria for md-select to check duplicate options in md-options

I have been using Angular Material for a while in my project. While using md-select, I am stuck to a problem wherein I am getting Duplicate md-option values error.
I am aware that md-options takes unique values and I am assigning an array to md-options. This is however, an array of objects. So I would like to know what is the criteria that is used to differentiate objects. The API do not say much about it.
My use case demands to change md-options of an md-select, based on selection from another md-select. So I am watching the selection of first md-select and firing a watch on its change and updating md-options of second md-select.
Below is the approach I am using to assign array to md-options:
$scope.$watch('search.selectedTrades', function(newTrades, oldTrades) {
if ((newTrades.length === 0)) {
$rootScope.search.selectedTrades = oldTrades;
return;
}
if ($rootScope.search.selectedTrades && $rootScope.search.selectedTrades.length > 0) {
if (!$rootScope.identity.isClusterManager) {
$rootScope.search.selectedTrades = newTrades;
SearchFilterData.setSelectedTrades(newTrades);
$rootScope.search.selectedClusters = [];
$scope.clusters = [];
$scope.subareas = [];
var clusterKeys = [];
$rootScope.search.selectedTrades.forEach(function(t) {
t.lstClusters.forEach(function(c) {
if (clusterKeys.indexOf(c.ClusterKey) == -1) {
clusterKeys.push(c.ClusterKey);
$scope.clusters.push(c);
}
})
})
}
} else {
$scope.clusters = [];
$scope.subareas = [];
$rootScope.search.selectedClusters = [];
$rootScope.search.selectedSubAreas = [];
SearchFilterData.setSelectedTrades($rootScope.search.selectedTrades);
}
});
In above code, clusterKey is a unique entity for each object. So I am using it to push unique values into array.
This however happens on few random scenarios, after I have selected and de-selected various options. Please advise what I am doing wrong and what is the criteria for marking two objects duplicate
You did not provide your markup, so I cannot be sure, but in my case the problem was caused by omitting the double curleys on the 'value' attribute in the md-option tag.
This is bad: Notice the missing curly braces
<md-option ng-repeat="item in vm.list" value="item.id">{{item.text}}</md-option>
This is not:
<md-option ng-repeat="item in vm.itemlist" value="{{item.id}}">{{item.text}}</md-option>
I believe the reason that this fails is that each item will be placed into the option list will be given a value of 'item.id' (literally). It will fail on the second iteration of the repeat.
Using the curly braces causes the value in 'item.id' to be used.
Hope this helps.
Try using ng-value instead of just value attribute.
<md-option ng-repeat="item in vm.list" ng-value="item.id">{{item.text}}</md-option>

What is right way to delete element from object Angular JS?

I have ng-repeat with function ng-click inside:
<div ng-repeat="item in data.education_list">
Delete
</div>
I pass object item from ng-repeat to function deleteEducation for deleting element from data.education_list.
So looks function:
$scope.deleteEducation = function (item){
$scope.data.education_list.splice($scope.data.education_list.indexOf(item), 1);
}
So this way works incorrect sometimes. When I have some element in ng-repeat and after delete item my template HTML is updated and removes row with another item, not that I deleted.
What is right way to delete?
data.education_list is array of objects if do {{data.education_list}}:
[{"name":"Test1","time":"01 Hun 2004 - 12 Sun 2006","Idusereducation":"86","usereducationIdToUser":"702","type":"1"}]
Problem two:
If I have object of objects instead array with key:
{"1" : {obj}, 2 : "obj"}
And if I try to delete element from object by key:
delete OBJ[1];
I get the same problem.
The easiest way is to use $index, this is a unique identifier that angular adds to track arrays.
<div ng-repeat="item in data.education_list">
Delete
</div>
If you are filtering a list
you will need to search for the index. Then do the splice. It is a little heavier, but required if you are filtering the list.
JS
this.removeItem = function(item) {
var index = $scope.data.education_list.indexOf(item);
if (index != -1) {
$scope.data.education_list.splice(index, 1);
}
};
HTML
ng-click="myctrl.removeItem(item)"
Working Example click to delete and .indexOf vs $index comparison
<div ng-repeat="item in data.education_list track by $index">
Delete
</div>
Then
$scope.deleteEducation = function (position){
$scope.data.education_list.splice(position, 1);
}
Came across the similar problem. In my case, I had to resolve as below just in case if it helps someone.
If you are dealing with objects, please note indexOf works for array not for an Object inside that array. You can do something like below to identify the index and handle this case;
$scope.removeReport = function(report) {
var index = $scope.contact.reports.map(function(r) { return r.id;}).indexOf(report.id);
if (index >= 0) {
$scope.contact.reports.splice(index, 1);
}
}
To remove a child item from a 2 dimensional array in an object, you need to define the parent item and then the child item to splice
e.g.
myObject[this.parentIndex].children.splice(this.childIndex,1);
myObject is an Object containing an array that includes children
parentIndex is the Index of the parent items
childIndex is the Index of the child items under the parent.
You can figure out your own way of looping through the parent and child arrays and deciding which child items to remove.

Order by with key value object in Angularjs

I have a select populated by a key/value object in Angular.
$scope.event_types = {
"CASE_STATE_CHANGE": "Case state change",
"NEW_ISSUE": "New Issue",
"CASE_REVERT": "Case Revert".......}
etc
However when I do an order by, it doesn't work.
<select
class="form-control"
name="chase2"
id="chase2"
ng-model="eventTypeFilter"
ng-change="updateEventFilterInput(eventTypeFilter)"
ng-options="key as value for (key , value) in event_types | orderBy:'value'">
Is this possible with this kind of array?
You cannot sort an Object. On most systems it will be sorted alphabetically. If you want to control the order that the elements will be presented you should use an array instead that guarantees ordering.
You could do something like:
var events_array = Object.keys(event_types)
.map(function (key) { return {key: key, value: event_types[key]} })
.sort(function(a,b) { return a.key < b.key; } );
and then use events_array on ng-options like:
<select ng-model="eventTypeFilter"
ng-options="event.key as event.value for event in events_array"></select>
Here is a jsfiddle (need to open console to see the output)
PS: you should consider sorting the values on the controller and then assign to the view as it is much more efficient than ordering on the view

Extjs4, filter store dynamically

I fill out an array dynamically with a list of Ids:
var allChildNodeIDs = [];
Ext.getCmp('categoriesTreePanel').getRootNode().eachChild(function(Mynode){
allChildNodeIDs.push(Mynode.data.idCategorie);
});
Then I want to filter a store according to all Ids contained in the array. For example if the array contains two values, I want that my store will be filtered like so:
myStore.filterBy(function(record) {
return (record.get('idCategorie') == allChildNodeIDs [1] && record.get('idCategorie') == allChildNodeIDs [2]);
});
But the array is filled out dynamically, and I don't know his length!
It seems like the sorting function in your example would always return false. I assume what you want to do is accept all the record which category is present into the array (i.e. that ou meant to use || instead of &&).
You can use Array's indexOf method.
Example:
myStore.filterBy(function(record) {
return allChildNodeIDs.indexOf(record.get('idCategorie')) !== -1;
});

AngularJS custom filter function

Inside my controller, I would like to filter an array of objects. Each of these objects is a map which can contain strings as well as lists
I tried using $filter('filter')(array, function) format but I do not know how to access the individual elements of the array inside my function. Here is a snippet to show what I want.
$filter('filter')(array, function() {
return criteriaMatch(item, criteria);
});
And then in the criteriaMatch(), I will check if each of the individual property matches
var criteriaMatch = function(item, criteria) {
// go thro each individual property in the item and criteria
// and check if they are equal
}
I have to do all these in the controller and compile a list of lists and set them in the scope. So I do need to access the $filter('filter') this way only. All the examples I found in the net so far have static criteria searches inside the function, they don't pass an criteria object and test against each item in the array.
You can use it like this:
http://plnkr.co/edit/vtNjEgmpItqxX5fdwtPi?p=preview
Like you found, filter accepts predicate function which accepts item
by item from the array.
So, you just have to create an predicate function based on the given criteria.
In this example, criteriaMatch is a function which returns a predicate
function which matches the given criteria.
template:
<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
{{ item }}
</div>
scope:
$scope.criteriaMatch = function( criteria ) {
return function( item ) {
return item.name === criteria.name;
};
};
Here's an example of how you'd use filter within your AngularJS JavaScript (rather than in an HTML element).
In this example, we have an array of Country records, each containing a name and a 3-character ISO code.
We want to write a function which will search through this list for a record which matches a specific 3-character code.
Here's how we'd do it without using filter:
$scope.FindCountryByCode = function (CountryCode) {
// Search through an array of Country records for one containing a particular 3-character country-code.
// Returns either a record, or NULL, if the country couldn't be found.
for (var i = 0; i < $scope.CountryList.length; i++) {
if ($scope.CountryList[i].IsoAlpha3 == CountryCode) {
return $scope.CountryList[i];
};
};
return null;
};
Yup, nothing wrong with that.
But here's how the same function would look, using filter:
$scope.FindCountryByCode = function (CountryCode) {
// Search through an array of Country records for one containing a particular 3-character country-code.
// Returns either a record, or NULL, if the country couldn't be found.
var matches = $scope.CountryList.filter(function (el) { return el.IsoAlpha3 == CountryCode; })
// If 'filter' didn't find any matching records, its result will be an array of 0 records.
if (matches.length == 0)
return null;
// Otherwise, it should've found just one matching record
return matches[0];
};
Much neater.
Remember that filter returns an array as a result (a list of matching records), so in this example, we'll either want to return 1 record, or NULL.
Hope this helps.
Additionally, if you want to use the filter in your controller the same way you do it here:
<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
{{ item }}
</div>
You could do something like:
var filteredItems = $scope.$eval('items | filter:filter:criteriaMatch(criteria)');

Resources