A filter is very similar to an factory or service in many regards but has the added advantage of behaving on a global scope once created. As we have previously seen, you can invoke a filter on both the data binding in your html or directly inside of your controller or directive by using the $filter service. Let’s break down the structure of a filter.
// To declare a filter we pass in two parameters to app.filter
// The first parameter is the name of the filter
// second is a function that will return another function that does the actual work of the filter
app.filter(‘myFilter’, function() {
// In the return function, we must pass in a single parameter which will be the data we will work on. We have the ability to support multiple other parameters that can be passed into the filter optionally
return function(input, optional1, optional2) {
var output;
// Do filter work here
return output;
}
});
Filters can be added in AngularJS to format data. AngularJS provides filters to transform data:
- currency Format a number to a currency format.
- date Format a date to a specified format.
- filter Select a subset of items from an array.
- json Format an object to a JSON string.
- limitTo Limits an array/string, into a specified number of elements/characters.
- lowercase Format a string to lower case.
- number Format a number to a string.
- orderBy Orders an array by an expression.
- uppercase Format a string to upper case.
Using filters in view templates
Filters can be applied to expressions in view templates using the following syntax:
{{ expression | filter }}
E.g. the markup {{ 12 | currency }} formats the number 12 as a currency using the currency filter. The resulting value is $12.00.
Filters can be applied to the result of another filter. This is called “chaining” and uses the following syntax:
{{ expression | filter1 | filter2 | … }}
Filters may have arguments. The syntax for this is
{{ expression | filter:argument1:argument2:… }}
E.g. the markup {{ 1234 | number:2 }} formats the number 1234 with 2 decimal points using the number filter. The resulting value is 1,234.00.
When filters are executed
In templates, filters are only executed when their inputs have changed. This is more performant than executing a filter on each $digest as is the case with expressions.
There are two exceptions to this rule:
- In general, this applies only to filters that take primitive values as inputs. Filters that receive Objects as input are executed on each $digest, as it would be too costly to track if the inputs have changed.
- Filters that are marked as $stateful are also executed on each $digest. Note that no AngularJS core filters are $stateful.
Adding Filters to Expressions
Filters can be added to expressions by using the pipe character |, followed by a filter. The uppercase filter format strings to upper case:
Example
<div ng-app=”myApp” ng-controller=”personCtrl”>
<p>The name is {{ lastName | uppercase }}</p>
</div>
The lowercase filter format strings to lower case:
Example
<div ng-app=”myApp” ng-controller=”personCtrl”>
<p>The name is {{ lastName | lowercase }}</p>
</div>
Adding Filters to Directives
Filters are added to directives, like ng-repeat, by using the pipe character |, followed by a filter:
Example
The orderBy filter sorts an array:
<div ng-app=”myApp” ng-controller=”namesCtrl”>
<ul>
<li ng-repeat=”x in names | orderBy:’country'”>
{{ x.name + ‘, ‘ + x.country }}
</li>
</ul>
</div>
The currency Filter
The currency filter formats a number value as a currency. When no currency symbol is provided, default symbol for current locale is used.
{{ expression | currency : ‘currency_symbol’ : ‘fraction’}}
Example
<div ng-app=”myApp” ng-controller=”costCtrl”>
<h1>Price: {{ price | currency }}</h1>
</div>
Number Filter
A number filter formats numeric data as text with comma and specified fraction size.
{{ number_expression | number:fractionSize}}
If a specified expression does not return a valid number then number filter displays an empty string. The following example demonstrates how to use number filter with number expression or a model property.
Example
<!DOCTYPE html>
<html >
<head>
<script src=”~/Scripts/angular.js”></script>
</head>
<body ng-app >
Enter Amount: <input type=”number” ng-model=”amount” /> <br />
100000 | number = {{100000 | number}} <br />
amount | number = {{amount | number}} <br />
amount | number:2 = {{amount | number:2}} <br />
amount | number:4 = {{amount | number:4}} <br />
amount | number = <span ng-bind=”amount | number”></span>
</body>
</html>
Date filter
Formats date to string based on the specified format.
{{ date_expression | date : ‘format’}}
Example
<!DOCTYPE html>
<html >
<head>
<script src=”~/Scripts/angular.js”></script>
</head>
<body ng-app>
<div ng-init=”person.DOB = 323234234898″>
Default date: {{person.DOB| date}} <br />
Short date: {{person.DOB| date:’short’}} <br />
Long date: {{person.DOB | date:’longDate’}} <br />
Year: {{person.DOB | date:’yyyy’}} <br />
</div>
</body>
</html>
Output –
Default date: Mar 30, 1980
short date: 3/30/80 8:47 AM
long date: March 30, 1980
Year: 1980
Uppercase/lowercase filter
The uppercase filter converts the string to upper case and lowercase filter converts the string to lower case.
Example
<!DOCTYPE html>
<html >
<head>
<script src=”~/Scripts/angular.js”></script>
</head>
<body ng-app>
<div ng-init=”person.firstName=’James’;person.lastName=’Bond'”>
Lower case: {{person.firstName + ‘ ‘ + person.lastName | lowercase}} <br />
Upper case: {{person.firstName + ‘ ‘ + person.lastName | uppercase}}
</div>
</body>
</html>
Output:
Lower case: james bond
Upper case: JAMES BOND
orderBy filter
The orderBy filter sorts an array based on specified expression predicate.
{{ expression | orderBy : predicate_expression : reverse}}
Example
<!DOCTYPE html>
<html>
<head>
<script src=”~/Scripts/angular.js”></script>
</head>
<body ng-app=”myApp”>
<div ng-controller=”myController”>
<select ng-model=”SortOrder”>
<option value=”+name”>Name (asc)</option>
<option value=”-name”>Name (dec)</option>
<option value=”+phone”>Phone (asc)</option>
<option value=”-phone”>Phone (dec)</option>
</select>
<ul ng-repeat=”person in persons | orderBy:SortOrder”>
<li>{{person.name}} – {{person.phone}}</li>
</ul>
</div>
<script>
var myApp = angular.module(‘myApp’, []);
myApp.controller(“myController”, function ($scope) {
$scope.persons = [{ name: ‘John’, phone: ‘512-455-1276’ },
{ name: ‘Mary’, phone: ‘899-333-3345’ },
{ name: ‘Mike’, phone: ‘511-444-4321’ },
{ name: ‘Bill’, phone: ‘145-788-5678’ },
{ name: ‘Ram’, phone: ‘433-444-8765’ },
{ name: ‘Steve’, phone: ‘218-345-5678’ }]
$scope.SortOrder = ‘+name’;
});
</script>
</body>
</html>
The filter Filter
The filter filter selects a subset of an array. The filter filter can only be used on arrays, and it returns an array containing only the matching items.
Example
Return the names that contains the letter “i”:
<div ng-app=”myApp” ng-controller=”namesCtrl”>
<ul>
<li ng-repeat=”x in names | filter : ‘i'”>
{{ x }}
</li>
</ul>
</div>
Filter an Array Based on User Input
By setting the ng-model directive on an input field, we can use the value of the input field as an expression in a filter. Type a letter in a input field, and the list will shrink/grow depending on the match:
- Jani
- Carl
- Margareth
- Hege
- Joe
- Gustav
- Birgit
- Mary
- Kai
Example
<div ng-app=”myApp” ng-controller=”namesCtrl”>
<p><input type=”text” ng-model=”test”></p>
<ul>
<li ng-repeat=”x in names | filter : test”>
{{ x }}
</li>
</ul>
</div>
Sort an Array Based on User Input
Click the table headers to change the sort order:
Name | Country |
Jani | Norway |
Carl | Sweden |
Margareth | England |
Hege | Norway |
Joe | Denmark |
Gustav | Sweden |
Birgit | Denmark |
Mary | England |
Kai | Norway |
By adding the ng-click directive on the table headers, we can run a function that changes the sorting order of the array:
Example
<div ng-app=”myApp” ng-controller=”namesCtrl”>
<table border=”1″ width=”100%”>
<tr>
<th ng-click=”orderByMe(‘name’)”>Name</th>
<th ng-click=”orderByMe(‘country’)”>Country</th>
</tr>
<tr ng-repeat=”x in names | orderBy:myOrderBy”>
<td>{{x.name}}</td>
<td>{{x.country}}</td>
</tr>
</table>
</div>
<script>
angular.module(‘myApp’, []).controller(‘namesCtrl’, function($scope) {
$scope.names = [
{name:’Jani’,country:’Norway’},
{name:’Carl’,country:’Sweden’},
{name:’Margareth’,country:’England’},
{name:’Hege’,country:’Norway’},
{name:’Joe’,country:’Denmark’},
{name:’Gustav’,country:’Sweden’},
{name:’Birgit’,country:’Denmark’},
{name:’Mary’,country:’England’},
{name:’Kai’,country:’Norway’}
];
$scope.orderByMe = function(x) {
$scope.myOrderBy = x;
}
});
</script>
Custom Filters
Writing your own filter is very easy: just register a new filter factory function with your module. Internally, this uses the filterProvider. This factory function should return a new filter function which takes the input value as the first argument. Any filter arguments are passed in as additional arguments to the filter function.
The filter function should be a pure function, which means that it should always return the same result given the same input arguments and should not affect external state, for example, other AngularJS services. AngularJS relies on this contract and will by default execute a filter only when the inputs to the function change. Stateful filters are possible, but less performant.
Filter names must be valid AngularJS Expressions identifiers, such as uppercase or orderBy. Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace your filters, then you can use capitalization (myappSubsectionFilterx) or underscores (myapp_subsection_filterx).
You can make your own filters by registering a new filter factory function with your module:
Example
Make a custom filter called “myFormat”:
<ul ng-app=”myApp” ng-controller=”namesCtrl”>
<li ng-repeat=”x in names”>
{{x | myFormat}}
</li>
</ul>
<script>
var app = angular.module(‘myApp’, []);
app.filter(‘myFormat’, function() {
return function(x) {
var i, c, txt = “”;
for (i = 0; i < x.length; i++) {
c = x[i];
if (i % 2 == 0) {
c = c.toUpperCase();
}
txt += c;
}
return txt;
};
});
app.controller(‘namesCtrl’, function($scope) {
$scope.names = [‘Jani’, ‘Carl’, ‘Margareth’, ‘Hege’, ‘Joe’, ‘Gustav’, ‘Birgit’, ‘Mary’, ‘Kai’];
});
</script>
Stateful Filters
It is strongly discouraged to write filters that are stateful, because the execution of those can’t be optimized by AngularJS, which often leads to performance issues. Many stateful filters can be converted into stateless filters just by exposing the hidden state as a model and turning it into an argument for the filter.
If you however do need to write a stateful filter, you have to mark the filter as $stateful, which means that it will be executed one or more times during the each $digest cycle.
index.html
<div ng-controller=”MyController”>
Input: <input ng-model=”greeting” type=”text”><br>
Decoration: <input ng-model=”decoration.symbol” type=”text”><br>
No filter: {{greeting}}<br>
Decorated: {{greeting | decorate}}<br>
</div>
script.js
angular.module(‘myStatefulFilterApp’, [])
.filter(‘decorate’, [‘decoration’, function(decoration) {
function decorateFilter(input) {
return decoration.symbol + input + decoration.symbol;
}
decorateFilter.$stateful = true;
return decorateFilter;
}])
.controller(‘MyController’, [‘$scope’, ‘decoration’, function($scope, decoration) {
$scope.greeting = ‘hello’;
$scope.decoration = decoration;
}])
.value(‘decoration’, {symbol: ‘*’});