A typical AngularJs filter is a synchronous function that should execute very quickly. For example, we can write a camel-case conversion filter using Lodash#camelCase
1 | angular.module('filters', []) |
The AngularJS assumes that your filter function returns the same result if given the same
arguments. Thus it caches the filtered results to avoid calling the filter. What if you
wanted to compute the result of the filter asynchronously? The filter cannot return a promise,
it must return some value, at least an undefined
. The best it can hope is to recompute the
value again in the future and return something else. Such filters are called
stateful,
and they require property $stateful
to be set to true
on the returned function.
1 | angular.module('App', []) |
The markup input field is
1 | <input ng-model="something">: {{something | details}} |
The function detailsFilter
will be called on each digest cycle. You can see the working example
below. Notice a new console message from detailsFilter
appears if you type in the input box
(which changes the value of the variable something
). It also appears if you click the button
that forces the digest cycle to execute.
Let us introduce an async component to the computed value. Imagine we want to call the server with the input and display the returned result. Or for simplicity, compute the result after 1 second. The result will be just a concatenation of the input. Here is a our code - we now must cache the computed value ourselves to avoid redoing the work on every digest cycle.
1 | angular.module('App', []) |
For demo purposes, I start with initial string foo
.
As you can see the string is computed only once. Now try typing in the input box and see how when a new value is computed, the text changes but only after 1 second. If you click the "force digest" button, the cached value is returned without any time out delay.
In practice, such filter allows to easily add dynamic server information to any template without manual scope / controller coding. Filter functions allow passing additional parameters from the HTML template, which allows great flexibility. For example, here is a filter for fetching Github user details.
1 | Github user <input ng-model="username"> |
Notice the markup simplicity, and here is the corresponding filter code that caches fetched user information object.
1 | .filter('details', function ($http) { |
You can see the filter in action below. Change the entered username to something else to see the UI update.
Happy hacking