Implement custom filters in AngularJS.

Filters are created by the Module.filter method, which takes two arguments: the name of the filter that will be created and a factory function that creates the worker function that will undertake the actual work. For example

angular.module("exampleApp")
    .filter("labelCase", function () {
        return function (value, reverse) {
            if (angular.isString(value)) {
                var intermediate =  reverse ? value.toUpperCase() : value.toLowerCase();
                return (reverse ? intermediate[0].toLowerCase() :
                    intermediate[0].toUpperCase()) + intermediate.substr(1);
            } else {
                return value;
            }
        };
    });

The filter is called labelCase and it formats string so that only the first letter is capitalized. Later, you can use it like this:

<tr ng-repeat="p in products | orderBy:[myCustomSorter, '-price'] | limitTo: 5">
    <td>{{p.name | labelCase }}</td>
    <td>{{p.category | labelCase:true }}</td>
    <td>{{p.expiry}}</td>
    <td class="text-right">{{p.price | currency }}</td>
</tr>

When we applied filter to the name we didn’t pass parameter to it. So AngularJS will pass null as the value for the second parameter.

Collection filter

The principle of creation of collection filter is the same, but it worth to show anyway.
Let’s say we want to create filter that skips a number of elements from array.

angular.module("exampleApp")
    .filter("skip", function () {
        return function (data, count) {
            if (angular.isArray(data) && angular.isNumber(count)) {
                if (count > data.length || count < 1) {
                    return data;
                } else {
                    return data.slice(count);
                }
            } else {
                return data;
            }
        }
    });

In worker function we check if data is an array and the count parameter is a number, perform some bounds checking and eventually we use slice method to skipe over the specified number of objects.
Later we use it like this:

<tr ng-repeat="p in products | skip:2 | limitTo: 5">
    <td>{{p.name}}</td>
    <td>{{p.category}}</td>
    <td>{{p.expiry}}</td>
    <td class="text-right">{{p.price | currency }}</td>
</tr>

In this example we chained to filters : skip and limitTo. The overall effect of these two filters is to skip first two and then select next five elements.

Building on Existing Filters

In the following example we combine skip and limitTo filters into the our custom one filter.

angular.module("exampleApp")
   .filter("take", function ($filter) {
        return function (data, skipCount, takeCount) {
            var skippedData = $filter("skip")(data, skipCount);
            return $filter("limitTo")(skippedData, takeCount);
        }
    });

The code is pretty much obvious, we just inject the $filter service in our filter and call already exited filters with it.

And html looks like this:

{{p.name}}{{p.category}}{{p.expiry}}{{p.price | currency }}

The cool thing is that we passed to parameters to our new filter, 2 for skip and 5 for take.

The full example with code available on Plunker

Share this post:Tweet about this on TwitterShare on Facebook0Share on LinkedIn0Share on Google+0Share on Reddit0Email this to someoneDigg this