Angular  

Learn AngularJS From the Beginning - Part Two

I am here to continue the discussion around AngularJS. Today, we will go through one of the main features of AngularJS, i.e., filter. Also, in case you have not had a look at our previous articles in this series, go through the following links: 

Now, in this article, we will discuss one of the main categories of AngularJS, i.e., filter. In AngularJS, a filter basically transforms the data before it’s processed by a model or directive and displayed in a view without making any changes in the original data in the $scope objects. Filters also allow us to display the same data in different formats in different parts of the application. In AngularJS, there are some built-in filters, and we can also create custom filters as per our requirements.

Built-in Filters in AngularJS

In AngularJS, there are several built-in filters that can be used to display the data in a desired format. Below, we discuss some of the main built-in filters of AngularJS for a single value.

Filter Name Description Sample Code
currency This filter formats currency value {{ p.price | currency}}
date This filter formats the date value {{ p.orderDate | date: “dd MMM yyyy” }}
{{ p.orderDate | date : “shortDate” }}
json This filter generates an object from a JSON string. <tr ng-repeat="p in products">
<td colspan="4">{{p | json}}</td>
</tr>
number This filter formats a numerical value. The number filter formats numeric data values to fix the number of decimal places displayed, rounding the value as required. {{ p.price | number : 0}} – no decimal values
{{ p.price | number : 2}} – 2 decimal values
uppercase
lowercase
These filters format a string value into all uppercase or lowercase letters. {{ p.city | lowercase }}
{{ p.state | uppercase }}
limitTo The limitTo filter restricts the number of items taken from an array of data objects. This can be useful when working with a layout that can accommodate only a certain number of items. <tr ng-repeat="p in products | limitTo:10">
The above example shows that in ng-repeat, it displays only the first 10 items in spite of the products containing more than 10 items in the array.
orderBy

 

This filter is used to sort the objects in an array. To sort the data in descending order, just mention the – sign in the filter expression. <tr ng-repeat="p in products | orderBy : ‘name’”>
For descending order
<tr ng-repeat="p in products | orderBy : ‘-name’”>

For the date filter, we need to provide an exact set of formats for date, month, and year. Below, I provide the list of string components supported by the date filters.

Component Description
yyyy A four-digit representation of the year (e.g., 2050)
yy A two-digit representation of the year (e.g., 50)
MMMM The full month name (e.g., January)
MMM Short representation of the month (e.g., Jan)
MM Numeric month, padded to two characters (e.g., 01)
M Numeric month, without padding (e.g., 1)
dd Day of month, padded to two characters (e.g., 02)
d Day of month, no padding (e.g., 2)
EEEE Full name of day of week (e.g., Tuesday)
EEE Short name of day of week (e.g., Tue)
HH Hour in day, 24-hour clock with padding to two characters (e.g., 02)
H Hour in day, 24-hour clock without padding (e.g., 2)
hh Hour in day, 12-hour clock with padding to two characters (e.g., 02)
h Hour in day, 12-hour clock without padding (e.g., 2)
mm Minutes in hours, padded to two characters (e.g., 02)
m Minutes in an hour without padding (e.g., 2)
ss Second in minutes, padded to two characters (e.g., 02)
s Second in minutes without padding (e.g., 2)
a Marker for a.m./p.m.
Z Four-character representation of time zone

To demonstrate the AngularJS default filter, follow the examples below,

App.js

var testApp = angular.module('TestApp', []);   

Filter.html

<!DOCTYPE html>  
<html ng-app="TestApp">  
<head>  
    <title>AngularJS Filter</title>  
    <script src="angular.js"></script>  
    <link href="../../RefStyle/bootstrap.min.css" rel="stylesheet" />  
    <script src="app.js"></script>  
    <script src="filter.js"></script>  
</head>  
<body ng-controller="FilterController">  
    <div class="panel panel-default">  
        <div class="panel-heading">  
            <h3>  
                Products  
                <span class="label label-primary">{{products.length}}</span>  
            </h3>  
        </div>  
        <div class="panel-body">  
            <table class="table table-striped table-bordered table-condensed">  
                <thead>  
                    <tr>  
                        <td>Name</td>  
                        <td>Category</td>  
                        <td>Offer Date</td>  
                        <td class="text-right">Quantity</td>  
                        <td class="text-right">Price</td>  
                    </tr>  
                </thead>  
                <tbody>  
                    <tr ng-repeat="p in products | orderBy :'name'">  
                        <td>{{p.name | uppercase}}</td>  
                        <td>{{p.category | lowercase}}</td>  
                        <td>{{getExpiryDate(p.expiry) | date:"dd MMM yy"}}</td>  
                        <td class="text-right">{{p.quantity | number:2 }}</td>  
                        <td class="text-right">{{p.price | currency}}</td>  
                    </tr>  
                </tbody>  
            </table>  
        </div>  
    </div>  
</body>  
</html>  

filter.js

testApp.controller('FilterController', function ($scope) {  
    $scope.products = [  
                    { name: "Sony LED", category: "TV", price: 40000, quantity:10, expiry: 30 },  
                    { name: "Samsung", category: "TV", price: 35640, quantity: 08, expiry: 21 },  
                    { name: "Z30", category: "Mobile", price: 36000, quantity: 5, expiry: 50 },  
                    { name: "Iphone 6", category: "Mobile", price: 55000, quantity: 6, expiry: 60 },  
                    { name: "Galaxy Note 3", category: "Mobile", price: 45000, quantity: 15, expiry: 50 },  
    ];  
  
    $scope.getExpiryDate = function (days) {  
        var now = new Date();  
        return now.setDate(now.getDate() + days);  
    }  
  
});  

The output of the above program is as follows.

Product list

Custom Filters in AngularJS

AngularJS not only supports the built-in filters, but we can create our own custom filter as per our requirement instead of using the built-in filters. Custom filters can be created by the module.filter method. Actually, internally AngularJS uses the filterprovider. This factory function must return a function that takes input values as arguments. The filter function should be a pure function, which means that it should be stateless and idempotent. Angular relies on these properties and executes the filter only when the inputs to the function change. The module.filter method actually takes two arguments – the name of the filter that needs to be created and a factory function that creates the worker function that will undertake the actual work.

Here, I created a custom filter which basically convert sany string value into Sentence case. 

CustomFilter.html 

<!DOCTYPE html>  
<html ng-app="TestApp">  
<head>  
    <title>AngularJS Custom Filter</title>  
    <script src="angular.js"></script>  
    <link href="../../RefStyle/bootstrap.min.css" rel="stylesheet" />  
    <script src="app.js"></script>  
    <script src="CustomFilter.js"></script>  
    <script src="CustomFilterCtrl.js"></script>  
</head>  
<body ng-controller="CustomFilterController">  
    <div class="panel panel-default">  
        <div class="panel-heading">  
            <h3>  
                Products  
                <span class="label label-primary">{{products.length}}</span>  
            </h3>  
        </div>  
        <div class="panel-body">  
            <table class="table table-striped table-bordered table-condensed">  
                <thead>  
                    <tr>  
                        <td>Name</td>  
                        <td>Category</td>  
                        <td>Offer Date</td>  
                        <td class="text-right">Quantity</td>  
                        <td class="text-right">Price</td>  
                    </tr>  
                </thead>  
                <tbody>  
                    <tr ng-repeat="p in products | orderBy :'name'">  
                        <td>{{p.name | properCase}}</td>  
                        <td>{{p.category | properCase : false}}</td>  
                        <td>{{getExpiryDate(p.expiry) | date:"dd MMM yy"}}</td>  
                        <td class="text-right">{{p.quantity | number:2 }}</td>  
                        <td class="text-right">{{p.price | currency}}</td>  
                    </tr>  
                </tbody>  
            </table>  
        </div>  
    </div>  
</body>  
</html>  

CustomFilter.js

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

CustomFilterCtrl.js

testApp.controller('CustomFilterController', function ($scope) {  
    $scope.products = [  
                    { name: "SONY LED", category: "TV", price: 40000, quantity: 10, expiry: 30 },  
                    { name: "SAMSUNG", category: "TV", price: 35640, quantity: 08, expiry: 21 },  
                    { name: "BLACKBERRY Z30", category: "Mobile", price: 36000, quantity: 5, expiry: 50 },  
                    { name: "IPHONE 6", category: "Mobile", price: 55000, quantity: 6, expiry: 60 },  
                    { name: "GALAXY NOTE 3", category: "Mobile", price: 45000, quantity: 15, expiry: 50 },  
    ];  
  
    $scope.getExpiryDate = function (days) {  
        var now = new Date();  
        return now.setDate(now.getDate() + days);  
    }  
  
});  

The output of the above program is.

Output 

In the above output, you can see that I defined the data in the controller file in upper case for the field of Name. Also, define the category field value in proper case. But in the HTML file, I use the custom filter properCase for the name field, and in case of the category field, I use the properCase filter with false arguments. Basically, I mentioned arguments as false, and then I simply make the opposite transformation of the proper case. 

Create a Collection Filter

The process for creating a filter that operates on a collection of objects is just the same, but is worth demonstrating anyway. In this section, I am going to build a skip filter that removes a specified number of items from the list of the array.

CollectionFilter.html

<!DOCTYPE html>  
<html ng-app="TestApp">  
<head>  
    <title>AngularJS Custom Collection Filter</title>  
    <script src="angular.js"></script>  
    <link href="../../RefStyle/bootstrap.min.css" rel="stylesheet" />  
    <script src="app.js"></script>  
    <script src="CollectionFilter.js"></script>  
    <script src="CollectionFilterCtrl.js"></script>
</head>  
<body ng-controller="CollectionFilterController">  
    <div class="panel panel-default">  
        <div class="panel-heading">  
            <h3>  
                Products  
                <span class="label label-primary">{{products.length}}</span>  
            </h3>  
        </div>  
        <div class="panel-body">  
            <table class="table table-striped table-bordered table-condensed">  
                <thead>  
                    <tr>  
                        <td>Name</td>  
                        <td>Category</td>  
                        <td>Offer Date</td>  
                        <td class="text-right">Quantity</td>  
                        <td class="text-right">Price</td>  
                    </tr>  
                </thead>  
                <tbody>  
                    <tr ng-repeat="p in products | orderBy :'name' | skipRec:2">  
                        <td>{{p.name }}</td>  
                        <td>{{p.category }}</td>  
                        <td>{{getExpiryDate(p.expiry) | date:"dd MMM yy"}}</td>  
                        <td class="text-right">{{p.quantity | number:2 }}</td>  
                        <td class="text-right">{{p.price | currency}}</td>  
                    </tr>  
                </tbody>  
            </table>  
        </div>  
    </div>  
</body>  
</html> 

CollectionFilterCtrl.js

testApp.controller('CollectionFilterController', function ($scope) {  
    $scope.products = [  
                    { name: "SONY LED", category: "TV", price: 40000, quantity: 10, expiry: 30 },  
                    { name: "SAMSUNG", category: "TV", price: 35640, quantity: 08, expiry: 21 },  
                    { name: "Blackberry Z30", category: "Mobile", price: 36000, quantity: 5, expiry: 50 },  
                    { name: "IPHONE 6", category: "Mobile", price: 55000, quantity: 6, expiry: 60 },  
                    { name: "GALAXY NOTE 3", category: "Mobile", price: 45000, quantity: 15, expiry: 50 },  
    ];  
  
    $scope.getExpiryDate = function (days) {  
        var now = new Date();  
        return now.setDate(now.getDate() + days);  
    }  
  
});  

CollectionFilter.js

testApp.filter("skipRec", 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;  
        }  
    }  
});  

The output of the above program is.

Product list output

In the above output, you can see that the first two records do not populate the screen since I provided 2 in the skipRec filter. Basically, this filter eliminates the first two records from the array and displays the other records. 

Read more articles on AngularJS.