AngularJS filters multiple selection inputs

I am really surprised that there is no documentation or questions regarding this more advanced filtering mechanism for AngularJS - this is important for any user interface.

I need to filter selection options that include the current item. The question is how can I combine all the options when we iterate over the elements included in our filter and return the correct results for each selection in the filtered list.

for example, if we have three regions - Canada, the United Kingdom, the United States - the entry of choice should look like this:

Canada [select] [option0] United Kingdom [option1] United States United Kingdom [select] [option0] Canada [option1] United States United States [select] [option0] Canada [option1] United Kingdom 

.. and so on...

HTML:

 <div ng-repeat="region in data.regions"> <h2> {{region.name}} </h2> <input ui-select2="version2" type="hidden" name="keywordsLocal-{{$index}}" class="region-keywords input-xlarge" data-ng-model="data.regions[$index].keywords" required-multiple /> <select ui-select2 id="copy-{{$index}}" ng-show="region.length > 1" class="input-xlarge" ng-click="_copy($event, $index)" data-ng-model="data.regions[$index].keywords"> <option value="">Use the same keywords as:</option> <option ng-repeat="region in data.regions | myFilter" value="{{region.keywords}}">{{region.name}}</option> </select> </div> 

JavaScript:

 app.filter('myFilter', function() { return function(items) { var group = []; for (var i = 0; i < items.length; i++) { group.push(items.name); } for (var i = 0; i < group.length; i++) { group[i].splice(i, 1); } return group; }; }); 
+6
source share
2 answers

I came up with a solution to this. this is a basic filter, but I actually pass the current index value in my ng-repeat for the filter:

Filter:

 app.filter('keywordFilter', function() { return function(items, name) { var arrayToReturn = []; for (var i = 0; i < items.length; i++) { if (items[i].name != name.name) { arrayToReturn.push(items[i]); } } return arrayToReturn; }; }); 

HTML

 <select ui-select2 id="copy-{{$index}}" class="input-xlarge" ng-change="_copy($index)" ng-options="region.name for region in data.regions | keywordFilter: {name: region.name}" data-ng-model="selectedKeywords"> <option value="">Use same keywords as:</option> </select> 
+1
source

There is a flaw in the selection, which does not include what is currently selected. I will include a mistake in the solution so that you can see it.

ng-options is what you need. Here is an example using 2 separate selections.

 <select ng-model='selectedCountry' ng-options='country.name for country in countries'></select> <select ng-model='selectedCountry' ng-options='country.name for country in filteredCountries()'></select> 

Here are snippets of $scope . Note that filterCountries simply returns countries, minus the selected country.

  $scope.countries = [{name:'United States'},{name:'United Kingdom'},{name:'Canada'}]; $scope.filteredCountries = function(){ var filteredCountries = []; angular.forEach($scope.countries, function(val, key){ if(val !== $scope.selectedCountry){ this.push(val); } },filteredCountries); return filteredCountries; }; 

The error you will notice is that as soon as you select the second, it will not display your selected value, since it is immediately filtered out of the parameters. This is not the best user interface.

Working example: http://plnkr.co/edit/cRBdkE3akCeBXYqfyHFO

Update: Since you cannot use ng-options with the AngularUI Select2 directive, here is plunkr with example 2: http://plnkr.co/edit/Hmt1OXYvtHOAZPzW7YK3?p=preview

Also, instead of the filterCountries function, as indicated above, watch will be more efficient. It will only run code when it detects a change in the observed value.

 $scope.$watch('version1model',function(){ $scope.filteredItems = []; angular.forEach($scope.items, function(val, key){ if(val.id != $scope.version1model){ this.push(val); } },$scope.filteredItems); }); 
+4
source

All Articles