ng-options filter based on selected value

Deblaton Jean-Philippe picture Deblaton Jean-Philippe · Feb 6, 2015 · Viewed 8.1k times · Source

I've to write a directive to edit labels for an app.

Each culture (eg: en-US) can have maximum 4 labels per property which are contained into a table :

 $scope.suffixes = ["DisplayName", "Description", "Hint", "Help"];


 <div class="clear" ng-repeat="label in labelModel | filter:cultureFilter">
      <select ng-options="suffix as suffix for suffix in suffixes | filter:suffixFilter(suffix, label.suffix)" ng-model="label.suffix" />

 </div>

and here are my controller functions :

    $scope.cultureFilter = function (label) {
        return (label.culture == $scope.labelState.culture);
    }

    $scope.suffixFilter = function (suffix, selectedValue) {

        //arguments are now : [undefined, "DisplayName"]

        return true; // :-(
    }

So far, I've been able to filter the ng-repeat based on the culture.

But for my ng-options, I have to filter the strings that are already used. But I also have to keep the current value selected. How can I tell my filter that some value shouldn't be filtered because it's the current selected value?

edit

Now, I'm able to receive the selected value, but I can't receive my suffix anymore

Answer

Josh picture Josh · Feb 6, 2015

You are almost there with using a filter function, but in your case, I think what you really need is a custom filter. They are actually trivial to write.

A filter is just a factory function registered with the .filter() helper.

You just need one that takes in the parameters you care about.

//Outer factory function
function SuffixFilter(){

  //Inner function which is our filter
  return function(items, ignoredItem){
     var filteredItems = [];

     angular.forEach(items, function(item){
        //Your filtering logic may be more complex
        // than this. It's only an example
        if(item == someCriteria || item == ignoredItem){
           filteredItems.push(item);
        }
     });

     return filteredItems;
  }
}

angular.module('myModule')
   .filter('suffixFilter', SuffixFilter);

And once you have your suffix filter registered, you can simply call it in your markup with the parameter you care about. Angular handles the rest.

<!-- Pass in the current selection to ignore -->
suffixes | suffixFilter:label.suffix

Update - Based on comment below:

The function parameter doesn't really work that way. It's expecting to evaluate to a function that can be called.

Technically you could return a function and use closures to accomplish what you want. Something like this:

<!-- In your markup -->
filter:suffixFilter(label.suffix)

//In your controller
$scope.suffixFilter = function (selectedValue) {

   //this is your actual filter here
   return function(item){

      //You have access to 'selectedValue' via
      // a closure
      return item == someCriteria || item === selectedValue;
   }
}

So again, while this is certainly possible, I think a custom filter is semantically cleaner.