10

In Angular, is there a way to modify the filter such that it only returns exact matches?

Example:

var words = [
    {   title: "ball"   },
    {   title: "wall"   },
    {   title: "all"    },
    {   title: "alloy"  }
];

var wordsFiltered = filter('filter')
( 
    words, 
    { 
        'title': 'all'
    } 
);  

The above will match 'ball', 'wall', 'all' and 'alloy'. But I would like it to only match 'all'. Any way to change it?

Ben
  • 15,938
  • 19
  • 92
  • 138

6 Answers6

19

UPDATE

Starting from AngularJS v.1.1.3 the exact filtering is provided natively:

Find words that exactly match title: 
<input ng-model="match.title" />
<br>
and exactly match type: 
<input ng-model="match.type" />
<hr>
<table>
  <tr ng-repeat="word in words | filter:match:true">
   <td>{{word.title}}</td> 
  </tr>
</table>

Plunker


Your question implies that you would want to match against multiple object properties so here's a filter that does that:

app.controller('AppController',
    [
      '$scope',
      function($scope) {
        $scope.match = {};
        $scope.words = [
          { title: "ball", type: 'object' },
          { title: "wall", type: 'object' },
          { title: "all", type: 'word' },
          { title: "alloy", type: 'material' }
        ];
        
      }
    ]
  );
  
app.filter('exact', function(){
  return function(items, match){
    var matching = [], matches, falsely = true;
    
    // Return the items unchanged if all filtering attributes are falsy
    angular.forEach(match, function(value, key){
      falsely = falsely && !value;
    });
    if(falsely){
      return items;
    }
    
    angular.forEach(items, function(item){ // e.g. { title: "ball" }
      matches = true;
      angular.forEach(match, function(value, key){ // e.g. 'all', 'title'
        if(!!value){ // do not compare if value is empty
          matches = matches && (item[key] === value);  
        }
      });
      if(matches){
        matching.push(item);  
      }
    });
    return matching;
  }
});
<body ng-controller="AppController">

  Find words that exactly match title: 
  <input ng-model="match.title" />
  <br>
  and exactly match type: 
  <input ng-model="match.type" />
  <hr>
  <table>
    <tr ng-repeat="word in words | exact:match">
     <td>{{word.title}}</td> 
    </tr>
  </table>  
</body>

PLUNKER

Community
  • 1
  • 1
Stewie
  • 60,366
  • 20
  • 146
  • 113
  • Thanks, but the filter must be called within the controller in my example, i.e. `var wordsFiltered = filter...`. There's a reason that there's no html in my example. How can I do that with your example? – Ben Aug 14 '13 at 22:33
  • Look here: http://docs.angularjs.org/api/ng.$filter. You can you it in Javascript and it will look like something like that: `newWords=$filter('exact')(words,'all')` – mchrobok Aug 14 '13 at 22:40
  • I added to my previous answer jsfiddle with example usage of filter in JS instead of HTML. – mchrobok Aug 14 '13 at 22:49
  • Inject your controller with `exactFilter` as in `app.controller('MyCtrl', ['$scope', 'exactFilter', function($scope, exactFilter)])` and use the filter as in: `$scope.filtered = exactFilter($scope.words, {title: 'ball'});`. You can use any filter in your controllers. – Stewie Aug 14 '13 at 23:04
  • Thanks, now how can I declare this filter within my service? (I've moved it from controller into service). Every example I see always starts with app.filter, yet I use the filter only once, in one place, so it has no business being in the app, but instead I want it where it is used, i.e. in the service (in this case). How can I do that? – Ben Aug 15 '13 at 07:58
  • I believe you should open a new question for that. – Stewie Aug 15 '13 at 08:53
9

Try this :

var words = [
    {   title: "ball"   },
    {   title: "wall"   },
    {   title: "all"    },
    {   title: "alloy"  }
];

var wordsFiltered = filter('filter')
( 
    words, 
    { 
        'title': 'all'
    },
    true
);
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47
Jamal dine Y
  • 91
  • 1
  • 1
3

You can use Regex to achieve a simple implementation:

<input ng-model="query" />
<tr ng-repeat="word in words | filter: myFilter">

In the controller:

$scope.myFilter = function (word) {
    if ($scope.query === '') return true;
    var reg = RegExp("^" + $scope.query + "$");
    return reg.test(word.title);
};
zs2020
  • 53,766
  • 29
  • 154
  • 219
2

I would create a new filter. Is this what you want?

HTML

<div ng-controller="MyCtrl">
     {{words | exactMatch:'all'}} !
</div>

JavaScript

var myApp = angular.module('myApp',[]);

myApp.filter('exactMatch', function() {
    return function(words, pattern) {
        var result = [];
        words.forEach(function (word) {
            if (word.title === pattern) {
                result.push(word);
            }
        });                
        return result;
    }
});

function MyCtrl($scope) {
    $scope.words = [
        {title: "ball", other: 1},
        {title: "wall", other: 2},
        {title: "all", other: 3},
        {title: "alloy", other: 4},
        {title: "all", other: 5},
    ];
}

JsFiddle: jsfiddle
More information about custom filters: filters, creating custom filters and using filters

If you want use filter in Javascript instead of html you should look here: jsfiddle

Aurelio
  • 24,702
  • 9
  • 60
  • 63
mchrobok
  • 1,947
  • 2
  • 20
  • 22
0

I created my own filter.

<select 
        ng-model="selection.neType" 
        ng-options="option.NE_TYPE_ID as option.NAME for option in networkElementTypes">
            <option value="">Todos</option>
    </select>

<select 
        ng-model="selection.neTypeVendor" 
        ng-options="option.VENDOR_TYPE_ID as option.NAME for option in networkElementTypeVendors | exactMatch: {FK_NE_TYPE_ID: selection.neType}">
                <option value="">All</option>
            </select>

    app.filter('exactMatch', function() {
        return function(elements, pattern) {    

            var result = [];        
            var fieldSearch = Object.keys(pattern)[0];

            elements.forEach(function (element) {  

                if (element[fieldSearch] == pattern[fieldSearch]) {
                    result.push(element);
                }
            });          

            return result;
        }
    });
Gabriel
  • 1,890
  • 1
  • 17
  • 23
0

angular-filter is a useful library of filters.

One of their filters is the where filter that does an exact match.

Greg Quinn
  • 1,927
  • 1
  • 23
  • 26