Filtering and Sorting a List

Problem

You wish to filter and sort a relatively small list of items all available on the client.

Solution

For this example we will render a list of friends using the ng-repeat directive. Using the built-in filter and orderBy filters we will filter and sort the friends list client-side.

<body ng-app="MyApp">
  <div ng-controller="MyCtrl">
    <form class="form-inline">
      <input ng-model="query" type="text"
        placeholder="Filter by" autofocus>
    </form>
    <ul ng-repeat="friend in friends | filter:query | orderBy: 'name' ">
      <li>{{friend.name}}</li>
    </ul>
  </div>
</body>

A plain text input field is used to enter the filter query and bound to the filter. Any changes are therefore directly used to filter the list.

The controller defines the default friends array:

app.controller("MyCtrl", function($scope) {
  $scope.friends = [
    { name: "Peter",   age: 20 },
    { name: "Pablo",   age: 55 },
    { name: "Linda",   age: 20 },
    { name: "Marta",   age: 37 },
    { name: "Othello", age: 20 },
    { name: "Markus",  age: 32 }
  ];
});

You can find the complete example on github.

Discussion

Chaining filters is a fantastic way of implementing such a use case as long as you have all the data available on the client.

The filter Angular.js Filter works on an array and returns a subset of items as a new array. It supports a String, Object or Function parameter. In this example we only use the String parameter, but given that the $scope.friends is an array of objects we could think of more complex examples where we use the Object param, as for example:

<ul ng-repeat="friend in friends |
  filter: { name: query, age: '20' } |
  orderBy: 'name' ">
  <li>{{friend.name}} ({{friend.age}})</li>
</ul>

That way we can filter by name and age at the same time. And lastly you could call a function defined in the controller, which does the filtering for you:

<ul ng-repeat="friend in friends |
  filter: filterFunction |
  orderBy: 'name' ">
  <li>{{friend.name}} ({{friend.age}})</li>
</ul>
$scope.filterFunction = function(element) {
  return element.name.match(/^Ma/) ? true : false;
};

The filterFunction must return either true or false. In this example we use a regular expression on the name starting with Ma to filter the list.