Removing the values from array by comparing substr value - angularjs

I have list of roles in an array $scope.role = []; I need to show the selected role in chip form with first 3 characters . So I used substr(0,3) in $scope.multiRoles where I am pushing my selected roles.My problem is when I am deleting the role , I am checking out the index and pushing the data back to $scope.role where the substring is pushed but not the original one.For example Doc is pushed instead of Doctor
$scope.role.push("Doctor","Engineer","Lawyer","Designer");
Add Role :
$scope.AddRole = function(index){
if($scope.model.role !== undefined ){
$scope.multiRoles.push($scope.model.role.substr(0,3));
var index = $scope.role.indexOf($scope.model.role);
$scope.role.splice(index,1);
}}
Remove Role:
$scope.removeRoles = function(index,data){
if(($scope.multiRoles!== null ) && ($scope.multiRoles.length>1))
var index = $scope.multiRoles.indexOf(data);
$scope.multiRoles.splice(index,1);
$scope.role.push(data);
};
HTML:
<span class="file-tag-baloon1" alue ="data"
ng-repeat="role in filteredRoles track by $index" >
<span>{{role}}</span>
<a ng-click="removeRoles($index,role)"class="remove1">X</a>
</span>

The problem is that when you delete role from $scope.role you lose information about this role hence you can't recover it. As a solution you can store full names of roles in both arrays and use substring for representation only in your html like {{multiRole.substr(0, 3)}}, so you will have two arrays with data that can go both ways without any losses.

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.

how to prevent duplicate in array push in angularjs

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'];

AngularJS: ng-repeat an array with keys

I have an array with unordered keys, and I want to display them. The problem is that angular repeats it for all the keys, even when they are not set.
this is the code:
<div ng-controller="MyCtrl">
Hello, {{a[10]}}!
<p ng-repeat="b in a">
1. {{b}}
</p>
</div>
<script>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.a = [];
$scope.a[10] = "aaa";
}
</script>
and this is the output:
Hello, aaa!
1.
1.
1.
1.
1.
1.
1.
1.
1.
1.
1. aaa
i want only the array keys that are set to output. no empty b's please...
here is a jsfiddle
In essence your problem is not AngularJS related but rather how JavaScript works.
If you have an empty array and you assign an element to position 10, then JavaScript will automatically resize the array to 11 elements (since an array index starts at zero) so the index is large enough to hold your element.
You could write extra code to filter the empty elements, but based on what you write, I think you would be better off with using an object to store your data.
I have created a plnkr for your convenience: http://plnkr.co/edit/apRLuJr4zqS2zbMz322Q?p=preview
// Array
$scope.sampleArray = [];
$scope.sampleArray[10] = 'test';
// Object
$scope.sampleObject = {};
$scope.sampleObject[10] = 'test';
As you can see the syntax is very similar, but the output is completely different.
By using an object, you will automatically eliminate the empty lines.
It will also keep your code simpler since you won't have to deal with the empty array elements.
Hope that helps!
There's plenty of ways to do a cleanup on your array inside the controller (e.g. using $watchcallback on a that would remove the empty elements from it whenever it changes).
Here's a solution that uses a simple custom filter, defined in a controller:
function MyCtrl($scope) {
$scope.namea = 'Superhero';
$scope.a = [];
$scope.a[10] = "aaa";
$scope.myFilter = function(item){
return item;
}
}
<p ng-repeat="b in a | filter:myFilter">
1. {{b}}
</p>
As stated in filter docs, the 'filter' filter can take a function:
function: A predicate function can be used to write arbitrary filters.
The function is called for each element of array. The final result is
an array of those elements that the predicate returned true for.

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