Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Given a controller with a $scope property that is an object with other properties rather than an array like below, how should I filter the ng-repeat set?

Here is a JSFiddle: http://jsfiddle.net/ZfGx4/110/

Controller:

function HelloCntl($scope, $filter) {
    $scope.friends = {
        john: {
            name: 'John',
            phone: '555-1276'
        },
        mary: {
            name: 'Mary',
            phone: '800-BIG-MARY'
        },
        mike: {
            name: 'Mike',
            phone: '555-4321'
        },
        adam: {
            name: 'Adam',
            phone: '555-5678'
        },
        julie: {
            name: 'Julie',
            phone: '555-8765'
        }
    };
}​

Template:

<div ng:app>
 <div ng-controller="HelloCntl">
  <input placeholder="Type to filter" ng-model="query">     
  <ul>
   <li ng-repeat="(id, friend) in friends | filter:query">
    <span>{{friend.name}} @ {{friend.phone}}</span>
   </li>
  </ul>
 </div>
</div>
share|improve this question
add comment

2 Answers

up vote 10 down vote accepted

I would change my data structure to an array. Anyway, here's another implementation to filter your friends object.

angular.module('filters',['utils'])
  .filter('friendFilter', function(utils){

    return function(input, query){
      if(!query) return input;
      var result = [];

      angular.forEach(input, function(friend){
        if(utils.compareStr(friend.name, query) ||
           utils.compareStr(friend.phone, query))
          result.push(friend);          
      });
      return result;
    };
  });

This iterates over the object only once, compares by name and phone and can be called like this.

<li ng-repeat="friend in friends | friendFilter:query">

I defined the compareStr in another module, but you don't really need to do it.

angular.module('utils', [])
  .factory('utils', function(){
    return{
      compareStr: function(stra, strb){
        stra = ("" + stra).toLowerCase();
        strb = ("" + strb).toLowerCase();
        return stra.indexOf(strb) !== -1;
      }
    };
  });

Don't forget to inject the filters module into your app

angular.module('app',['filters'])

Here's the full example: http://jsbin.com/acagag/5/edit

share|improve this answer
add comment

I guess you can't do it directly with 'filter'. Looking at the code in angular.js, these are the first lines of the filter function:

function filterFilter() {
  return function(array, expression) {
    if (!(array instanceof Array)) return array;

So if it receives something different from an array, it does nothing.

Here is one way to do it, not sure if I would recommend it, but it's is an idea:

In the controller, just convert to an array before passing it to the filter:

$scope.filteredFriends = function() {
    var array = [];
    for(key in $scope.friends) {
        array.push($scope.friends[key]);
    }
    return $filter('filter')(array, $scope.query);
}

And the ng-repeat:

<li ng-repeat="friend in filteredFriends()">

Example: http://jsbin.com/acagag/2/edit

Maybe a better solution is to write a custom filter.

share|improve this answer
 
I knew the filter filter required arrays, but I didn't know they used instanceof Array to check whether something was an array! I would've expected a different kind of check (perfectionkills.com/…). Anyway, I took your example as a base for my example. –  jaime Dec 15 '12 at 4:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.