Filters

A filter formats a value for display without changing the underlying data — the same idea as a Unix pipe, and in fact it uses the same | symbol. AngularJS ships with a handful of filters for the formatting jobs that come up in nearly every app: currency, dates, and text case.

Using a built-in filter

A filter goes after the value it applies to, separated by |, directly inside an expression:

HTML receipt.html
<div ng-app="" ng-init="price = 42.5, purchased = new Date(2026, 8, 9)">
  <p>Price: {{ price | currency }}</p>
  <p>Purchased: {{ purchased | date:'longDate' }}</p>
</div>
Rendered output
Price: $42.50
Purchased: September 9, 2026

currency adds the $ sign and rounds to two decimal places automatically; date:'longDate' takes an optional format-string argument, passed after a colon, telling it exactly how to render the date. Neither filter changed price or purchased themselves — only what got displayed.

Chaining filters

Filters can be stacked, each one operating on the previous filter's output:

HTML shout.html
<div ng-app="" ng-init="title = 'server error'">
  <p>{{ title | uppercase | limitTo:6 }}</p>
</div>
Rendered output
SERVER

uppercase runs first, producing "SERVER ERROR", and limitTo:6 then truncates that result to its first 6 characters — order matters, exactly like piping commands together in a terminal.

Filtering an ng-repeat list

The filter filter is a special case — used inline with ng-repeat to show only items matching some criteria, without writing any filtering logic in the controller:

HTML search.html
<div ng-app="" ng-init="names = ['Priya', 'Sam', 'Priyanka', 'Alex'], query = 'pri'">
  <li ng-repeat="n in names | filter:query">{{ n }}</li>
</div>
Rendered output
• Priya
• Priyanka

filter:query keeps only the array entries that case-insensitively contain query's current value — bind query to a text input with ng-model and this becomes a live search box with zero JavaScript filtering logic written by hand.

Performance note: both filter and any custom filter you write get re-run on every single digest cycle, for every item in the array — not just when the underlying data actually changes. On a list of a few dozen items this is invisible; on a list of several thousand, a filter (especially one doing real work, like a case-insensitive substring search) can become a measurable slowdown. This is the same underlying cost as the digest cycle re-checking all your bindings, just applied to filtering specifically.