AngularJS Custom Filters

AngularJS Filters

Part 2 - Custom Filters

AngularJS Custom Filters are very easy, just create and register the filter factory function in module. It returns a new filter function by passing first argument as input. We need custom filters to fulfill or cover modern business requirements. In case you have landed directly here then click here Learn AngularJS Filters Part 1 before proceed.

Creating Custom Filters

Remember following things

  1. It should be pure function, which should be stateless and unchanged key values.
  2. Not rely on other Angular services.
  3. It will by default executed in Angular when input to the function changed.
  4. Filter name must be valid Angular expression identifier such as lowercase or camelCase. Hyphens and dots are not allowed in filter name.

Example

/*
app.js
custom Filters
*/
'use strict';

angular.module('myApp', [])

.controller('customFilterController', ['$scope', function($scope) {
  $scope.orderItems = [
                        {orderID: 1, name: 'Apple', qty: 1, price: 14.50, amount: 14.50},
                        {orderID: 1, name: 'Banana', qty: 1, price: 8.10, amount: 8.10},
                        {orderID: 2, name: 'Orange', qty: 2, price: 11.50, amount: 23.00},
                        {orderID: 2, name: 'Apple', qty: 3, price: 14.50, amount: 43.50},
                        {orderID: 2, name: 'Grape', qty: 1, price: 6.50, amount: 6.50},
                        {orderID: 3, name: 'Apple', qty: 1, price: 14.50, amount: 14.50},
                        {orderID: 3, name: 'Banana', qty: 4, price: 8.10, amount: 32.40},
                        {orderID: 3, name: 'Grape', qty: 2, price: 6.50, amount: 13.50},
                        {orderID: 4, name: 'Orange', qty: 3, price: 11.50, amount: 34.50},
                        {orderID: 4, name: 'Grape', qty: 1, price: 6.50, amount: 6.50}
                      ];
}])

// custom filter for return unique values
.filter('unique', function() {
  return function(collection, keyname) {
    var output = [],
        keys = [];

    angular.forEach(collection, function(item) {
      var key = item[keyname];
      if(keys.indexOf(key) === -1) {
          keys.push(key);
          output.push(item);
      }
    });

    return output;
  }
})

// custom filter for count
.filter('count', function() {
  return function(data, key) {
    if (typeof (data) === 'undefined' || typeof (key) === 'undefined') {
        return 0;
    }

    var count = 0;
    for (var i = data.length - 1; i >= 0; i--) {
        count += 1;
    }

    return count;
  }
})

// custom filter for sum
.filter('sum', function() {
  return function(data, key) {
    if (typeof (data) === 'undefined' || typeof (key) === 'undefined') {
        return 0;
    }

    var sum = 0;
    for (var i = data.length - 1; i >= 0; i--) {
        sum += parseFloat(data[i][key]);
    }

    return sum;
  }
});
<!DOCTYPE html>
<!--
index.html
using angularjs cutom filters
-->
<html ng-app="myApp">
<head>
  <title>AngularJS Custom Filters </title>

  <!-- bootsrap CDN -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
  <div class="container" ng-controller="customFilterController">
    <h4>Order Items</h4>
    <div class="row">
      <div class="col-md-6">
        Select Order #:
        <select class="form-control" ng-model="selectedOrder" ng-options="order.orderID for order in orderItems | unique:'orderID'" ng-change="selectOrder(selectedOrder)">
          <option value="">(All)</option>
        </select>
      </div>
      <div class="col-md-6">
        Select Item:
        <select class="form-control" ng-model="selectedItem" ng-options="order.name for order in orderItems | unique:'name'" ng-change="selectItem(selectedItem)">
          <option value="">(All)</option>
        </select>
      </div>
    </div>
    <div class="row">
      <div class="col-md">
        <br>
        <table class="table table-striped table-bordered bg-white">
          <thead>
            <tr>
              <th>Order #</th>
              <th>Name</th>
              <th>Qty</th>
              <th>Rate</th>
              <th>Amount</th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="item in orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true">
              <td>{{item.orderID}}</td>
              <td>{{item.name}}</td>
              <td style="text-align:right">{{item.qty}}</td>
              <td style="text-align:right">{{item.price | number:2}}</td>
              <td style="text-align:right">{{item.amount | currency}}</td>
            </tr>
          </tbody>
          <tfoot>
            <tr style="font-weight:bold;">
              <th>Rows - {{orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true | count:'orderID'}}</th>
              <th style="text-align:right">Total</th>
              <th style="text-align:right">{{orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true | sum:'qty'}}</th>
              <th></th>
              <th style="text-align:right">{{orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true | sum:'amount' | currency}}</th>
            </tr>
          </tfoot>
        </table>
      </div>
    </div>
  </div>

  <!-- AngularJS CDN -->
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
  <script src="app.js" type="text/javascript"></script>
</body>
</html>

Order Items

Select Order #:
Select Item:

Order # Name Qty Rate Amount
{{item.orderID}} {{item.name}} {{item.qty}} {{item.price | number:2}} {{item.amount | currency}}
Rows - {{orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true | count:'orderID'}} Total {{orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true | sum:'qty'}} {{orderItems | filter:{'orderID':selectedOrder.orderID}:true | filter:{'name':selectedItem.name}:true | sum:'amount' | currency}}