angularJs exclude already selected items from array - javascript

I have an array of objects in $scope.currentSChannels.scgsLink This array of objects have something like
$scope.currentSChannels.scgsLink = [{channelId:1, sCgsLinkId:1, groupNo:1, percentage: 50, expireHrs:4},{channelId:1, sCgsLinkId:2, groupNo:2, percentage:50, expireHrs:1}]
and I also have the following select list
<div class="col-md-4">
<select class="form-control" ng-model="newLink.groupNo"
name="groupNo" id="groupNo"
ng-options="t.value as t.text for t in metaData.spGroups"></select>
</div>
I need to filter that list to not show already selected items in the $scope.currentSChannels.scgsLink groupNo column. I looked at http://christian.fei.ninja/Angular-Filter-already-selected-items-from-ng-options/ and also at AngularJS ng-options to exclude specific object and both seem to be close but not enough as I need to filter against an array and a particular column in that array. How should I implement that filtering?

The template is getting a bit tricky. Assuming selectedLink is the variable that points to the selected groupNo
ng-options="t.value as t.text for t in metaData.spGroups | filter: {value: '!' + currentSChannels.scgsLink[selectedLink].groupNo}"
See this fiddle : the second select contains the same collection as the first one, excluded what is already selected.
Edit: Solution above is for excluding elements according to one value. So as to exclude the elements according to a collection of values, a custom filter would suit best:
Filter
app.filter('channelFilter', function () {
return function (metadata, exclusions) {
var filterFunction = function (metadata) {
// return the metadata object if exclusions array does NOT contain his groupNo
return !exclusions.some(function (exclusion) {
return exclusion.groupNo === metadata.value;
});
};
return metadatas.filter(filterFunction);
};
});
Usage
ng-options="metadata in metadatas | channelFilter: exclusions"
Template
ng-options="t.value as t.text for t in metaData.spGroups | channelFilter: currentSChannels.scgsLink"
Fiddle
That said, would be more efficient to group selected links by groupNo to avoid searches in the array, and filter in the controller.

I wanted to make it a bit more generic, so I've done the following
http://jsfiddle.net/96m4sfu8/
app.filter('excludeFrom', function () {
return function (inputArray, excludeArray, excludeColumnName, inputColumnName) {
if (inputColumnName==undefined)
inputColumnName = 'value';
var filterFunction = function (inputItem) {
return !excludeArray.some(function (excludeItem) {
return excludeItem[excludeColumnName] === inputItem[inputColumnName];
});
};
return inputArray.filter(filterFunction);
};
});

Related

How to filter array of items with multiple dropdowns on single angularjs custom filter function?

I am facing a problem with the filter function in Angularjs, here I used a common function ng-change for multiple a dropdown. But when I select All(default options) I am getting an empty array of filtered items.
Here is my code
Javascript:
function customFilters() {
vm.filteredItems = $filter('filter')(vm.claimsResData, {
status: vm.status,
member: vm.member,
treatment: vm.treatment
});
}
Html:
<select ng-model="vm.member" class="form-control"
ng-options="names for names in vm.memberNames"
ng-change="vm.customFilters()">
<option value="">All Members</option>
</select>
Any help would be appreciated.
Thanks.
Update your function as below, because when you want to exclude a key from filter you've to pass undefined to its value, but in your code you are passing blank string i.e., ""
function customFilters() {
vm.filteredItems = $filter('filter')(vm.claimsResData, {
status: vm.status,
member: vm.member || undefined,
treatment: vm.treatment
});
}
Only add the selection to the pattern object if the selection is truthy:
function customFilters() {
var patternObj = {}
vm.status && patternObj.status = vm.status;
vm.member && patternObj.member = vm.member;
vm.treatment && patternObj.treatment = vm.treatment;
vm.filteredItems = $filter('filter')(vm.claimsResData, patternObj);
}
A pattern object is used to filter specific properties on objects contained by the array. When that property exists on the pattern object, the objects in the array must have that property.
For more information, see
AngularJS filter Filter API Reference

Replace object with existing value in array in AngularJS

I have an ng-repeat with a select in every item.
The user can select a value (trigging a function that pushes the an object into an array), but they can also change their mind, in which case the code just pushes a second object with the new value, duplicating the first one.
How could I manage to actually delete existing values, leaving only the last one on every ng-change?
Here's my HTML:
<select ng-change="insertproduct(pa.nom, basket)" ng-model="basket">
<option ng-repeat="select in numberofproducts">{{select}}</option>
</select>
And my javascript:
$scope.numberofproducts = [1,2,3,4,5,6,7,8,9,10]
$scope.singleorder = [];
$scope.insertproduct = function(nom, basket){
$scope.numero = {
'producte': nom,
'numero': basket
};
$scope.singleorder.push($scope.numero);
console.log($scope.singleorder);
}
The idea is to create a condition in which if the array contains an object with the parameter ´producte´ equal to the new one, delete the existing and push the new one.
Any tips?
First, use the findIndex method to check if an object with the same property is already in the singleorder array.
function duplicateOrder(order) {
return order.producte === nom;
}
var index = $scope.singleorder.findIndex(duplicateOrder);
Note: browser support for findIndex is limited; it is not supported in Internet Explorer.
Then remove the item with splice:
if(index > -1){
$scope.singleorder.splice(index, 1);
}
You can then push the new one in.
You should also clean up your coding style: don't mix french and english, and use either camelCase or snake_case for your functions to improve readability.
Observation :
Use AngularJS ngOptions attribute instead of ng-repeat.
You can check the index of the element in an array if that was already there you can easily remove previous one.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl',function($scope) {
$scope.numberofproducts = [1,2,3,4,5,6,7,8,9,10]
$scope.newArray = [];
$scope.insertproduct = function(basket) {
var prevIndex = $scope.newArray.indexOf(basket);
if(prevIndex > -1) {
$scope.newArray.splice(prevIndex, 1);
} else {
$scope.newArray.push(basket);
}
console.log($scope.newArray);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<select ng-change="insertproduct(basket)" ng-model="basket" ng-options="select for select in numberofproducts">
</select>
</div>

How to pass ng-repeat item property to filter?

I created a filter that I want to pass an item property, and not the item itself. Is that possible?
The following does not work (item.param1 fails):
ng-reapeat="item in items | filter : fnFilter(item.param1)"
$scope.fnFilter = function(value) {
return value == "test";
}
Your question is quite unclear sdince you don't tell really what is your goal.
So if i just restrict to what i see there and following the link Angular filter exactly on object key already provided by #CeylanMumumKocabas you would have
ng-repeat="item in items | filter:{'param1': 'test'}"
Now let's consider you want something more complex : the only way i see would be to pass the name of the attribute to the filter :
ng-reapeat="item in items | myFilter:'param1'"
myApp.filter('myFilter', function () {
return function(inputs,attributeName) {
var output = [];
angular.forEach(inputs, function (input) {
if (input[attributeName] == 'test')
output.push(input);
});
return output;
};
});
Note that if you want to go more than one level, you'll have to use $eval or make add some code for this to work.

Filter ng-repeat json result against array

At the moment I have a json result which is displayed in an ng-repeat that I would like to have filtered based on a separate object or array of data:
Controller.js
$scope.jsonResult = [
{
"id": "a123"
},
{
"id": "b456"
}
]
HTML
<span ng-repeat="r in jsonResult">{{r.id}}</span>
What I am attempting to achieve is to create a separate array of info and then use this data to filter the ng-repeat results that display in my HTML.
$scope.itemsToFilter = ["b456","foo"]
Since an item within my itemsToFilter array matches an object within my jsonResult scope, I would like that not to display within my ng-repeat within the HTML. Is this something I should write a custom filter for? Sorry I am very new to Angular.
You can create an Angular filter which returns the array filtered by items' ids which match your blacklist:
angular.module("yourAppName")
.filter("filterArrayByBlacklist", function() {
blackList = ["b456","foo"];
return function(array) {
return array.filter(function(item) {
return blackList.indexOf(item.id) === -1; // item id not found in blacklist
});
};
});
You can then filter the ng-repeat by your filter function:
<span ng-repeat="r in jsonResult | filterArrayByBlacklist">{{r.id}}</span>
See this plnkr for a demo: http://plnkr.co/edit/VK3jiVBpL0e1G06WmPZq
The easiest way is by using a custom filter. A quick filter can be written like this:
$scope.filterByStrings = function (item) {
return ($scope.itemsToFilter.indexOf(item.id) === -1);
};
And called like this:
<div ng-repeat="item in data | filter:filterByStrings ">
<p>{{item.id}}</p>
</div>
Here is the fiddle.

Filter one collection based on another with AngularJS custom filter

I need to filter a collection of objects based on another collection in angularjs. I need to create a custom filter I'm sure but have found no examples that are similar. So I have a list of "equipmentOptions" (basically they are product customizations, ex. premium stereo in your car). Some "equipmentOptions" are not available unless you have already selected other "equipmentOptions".
The equipmentOptions available are $scope.product.equipmentOptions.
The equipmentOptions that have been selected are $scope.product.selectedOptions.
equipmentOptions has a property requiredParents which is a collection of id's for other equipment options. If any of these requiredParents exist in $scope.product.selectedOptions, then the equipmentOption should be shown.
Here's what I've tried so far to no avail:
<div ng-repeat="option in product.equipmentOptions | optionsFilter:product.selectedOptions">
optionsFilter.js
myApp.filter('optionsFilter', function () {
return function (selectedOptions) {
// I'm just trying to get the list of selected options as well as the current option here for filtering, how do I get the current option?
};
});
Your first argument is the list of product.equipmentOptions. The second argument is product.selectedOptions. Write your filter like this:
myApp.filter('optionsFilter', function() {
return function(equipmentOptions, selectedOptions) {
var filteredOptions = [];
angular.forEach(equipmentOptions, function(option) {
if(/*option meets criteria*/) {
filteredOptions.push(option);
}
});
return filteredOptions;
}
});

Categories

Resources