@ngdoc overview
@name Tutorial: 103 Filtering
@description

### Simple setup

UI-Grid allows you to filter rows. Just set the `enableFiltering` flag in your grid options (it is off by default).

Filtering can be disabled at the column level by setting `enableFiltering: false` in the column def. See the "company" column below for an example.

The filter field can be pre-populated by setting `filter: { term: 'xxx' }` in the column def.  See the "gender" column below.  Once
the grid has rendered changes to the columnDef don't reflect in the grid - if they did then users would have their changes to filters
overwritten every time the grid refreshed.  If you want to programatically modify filters after initial render then modify
grid.column[i].filters[0] directly.

### Conditon

The `filter` object introduced above may also specify a `condition`, which defines how rows are chosen as matching the filter term. UI-Grid comes with several conditions
out-of-the-box, which are defined by `uiGridConstants.filter.*`. See the "email" column below.

If no condition is set, UI-Grid will take a best guess based on the contents of the filter field. Even basic wildcard (*) use is supported!

If you want to create your own filtering logic, the `condition` field of the `filter` object can also be a function that gets run for each
row. Such a function has the following signature:

```javascript
function myCustomSorter(searchTerm, cellValue, row, column) {
  // Custom logic that returns true if `row`
  // passes the filter and false if it should
  // be filtered out
  return booleanResult;
}
```

For an example of this, see the "phone" column below for an example of this; the custom filter condition makes sure to strip the phone number of everything
except digits to compare to the search term.

You can also optionally create a custom filter condition that doesn't require a term to be provided by the user - for example if you're matching
to a variable that you're setting within your code.  If you want to do this, you can set `noTerm: true` inside the filter, and the filter will
run even when no term is provided.  The filter box will, however, still be shown.

### Placeholder

Set the `placeholder` property on the `filter` object to add a `placeholder=""` attribute to the input element. This is set for the "email" and "age" columns below.

### Multiple filter fields

Occasionally, you may want to provide two or more filters for a single column. This can be accomplished by setting a `filters` array instead of a `filter` object.
The elements of this array are the same as the contents of the `filter` object in all the previous examples. In fact, `filter: { term: 'xxx' }` is just an alias
for `filters: [{ term: 'xxx' }]`. See the "age" column below for an example.

### Date filters
The example also includes date filters.  These work, however there isn't a date chooser in the filter widget - so you may need to implement a custom field
if you want to filter dates in this way.

### Dropdowns
Filtering supports dropdowns, in order to set a particular column to use a dropdown you should set:
  `type: uiGridConstants.filter.SELECT`
and
  `selectOptions: [ { value: 'x', label: 'decode of x' } , .... ]`


If you need to internationalize the labels you'll need to complete that before providing the selectOptions array.

### Cancel icon
By default the filter shows a cancel X beside the dropdown. You can set `disableCancelFilterButton: true` to suppress
this button.

### Programmatic setting of filters
You can set filters

In this example we've provided a "toggle filters" button to allow you to turn the filter row on and off.  To
still visually indicate which columns are filtered even when the filters aren't present, we've used the headerCellClass
to make any columns with a filter condition have blue text.

### cellFilters

By default the filtering will not use the formatted value after applying `cellFilters`, it uses the raw value from the row. The {@link api/ui.grid.class:GridOptions.columnDef#filterCellFiltered filterCellFiltered}
columnDef option will cause filtering to be applied after the `cellFilters` are evaluated, as seen on the "Long Date" field.

### Single filter box (similar to 2.x)


Refer {@link 321_singleFilter singleFilter tutorial}, it is possible to implement this using a rowsProcessor.

@example
<example module="app">
  <file name="app.js">
    var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid']);

    app.controller('MainCtrl', ['$scope', '$http', 'uiGridConstants', function ($scope, $http, uiGridConstants) {
      var today = new Date();
      var nextWeek = new Date();
      nextWeek.setDate(nextWeek.getDate() + 7);

      $scope.highlightFilteredHeader = function( row, rowRenderIndex, col, colRenderIndex ) {
        if( col.filters[0].term ){
          return 'header-filtered';
        } else {
          return '';
        }
      };

      $scope.gridOptions = {
        enableFiltering: true,
        onRegisterApi: function(gridApi){
          $scope.gridApi = gridApi;
        },
        columnDefs: [
          // default
          { field: 'name', headerCellClass: $scope.highlightFilteredHeader },
          // pre-populated search field
          { field: 'gender', filter: {
              term: '1',
              type: uiGridConstants.filter.SELECT,
              selectOptions: [ { value: '1', label: 'male' }, { value: '2', label: 'female' }, { value: '3', label: 'unknown'}, { value: '4', label: 'not stated' }, { value: '5', label: 'a really long value that extends things' } ]
            },
            cellFilter: 'mapGender', headerCellClass: $scope.highlightFilteredHeader },
          // no filter input
          { field: 'company', enableFiltering: false, filter: {
            noTerm: true,
            condition: function(searchTerm, cellValue) {
              return cellValue.match(/a/);
            }
          }},
          // specifies one of the built-in conditions
          // and a placeholder for the input
          {
            field: 'email',
            filter: {
              condition: uiGridConstants.filter.ENDS_WITH,
              placeholder: 'ends with'
            }, headerCellClass: $scope.highlightFilteredHeader
          },
          // custom condition function
          {
            field: 'phone',
            filter: {
              condition: function(searchTerm, cellValue) {
                var strippedValue = (cellValue + '').replace(/[^\d]/g, '');
                return strippedValue.indexOf(searchTerm) >= 0;
              }
            }, headerCellClass: $scope.highlightFilteredHeader
          },
          // multiple filters
          { field: 'age', filters: [
            {
              condition: uiGridConstants.filter.GREATER_THAN,
              placeholder: 'greater than'
            },
            {
              condition: uiGridConstants.filter.LESS_THAN,
              placeholder: 'less than'
            }
          ], headerCellClass: $scope.highlightFilteredHeader},
          // date filter
          { field: 'mixedDate', cellFilter: 'date', width: '15%', filter: {
              condition: uiGridConstants.filter.LESS_THAN,
              placeholder: 'less than',
              term: nextWeek
            }, headerCellClass: $scope.highlightFilteredHeader
          },
          { field: 'mixedDate', displayName: "Long Date", cellFilter: 'date:"longDate"', filterCellFiltered:true, width: '15%',
          }
        ]
      };

      $http.get('/data/500_complex.json')
        .success(function(data) {
          $scope.gridOptions.data = data;
          $scope.gridOptions.data[0].age = -5;

          data.forEach( function addDates( row, index ){
            row.mixedDate = new Date();
            row.mixedDate.setDate(today.getDate() + ( index % 14 ) );
            row.gender = row.gender==='male' ? '1' : '2';
          });
        });

      $scope.toggleFiltering = function(){
        $scope.gridOptions.enableFiltering = !$scope.gridOptions.enableFiltering;
        $scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
      };
    }])
    .filter('mapGender', function() {
      var genderHash = {
        1: 'male',
        2: 'female'
      };

      return function(input) {
        if (!input){
          return '';
        } else {
          return genderHash[input];
        }
      };
    });
  </file>
  <file name="index.html">
    <div ng-controller="MainCtrl">
      You can use asterisks to fuzz-match, i.e. use "*z*" as your filter to show any row where that column contains a "z".
      <br>
      <br>
      <strong>Note:</strong> The third column has the filter input disabled, but actually has a filter set in code that requires every company to have an 'a' in their name.
      <br>
      <br>
      <button id='toggleFiltering' ng-click="toggleFiltering()" class="btn btn-success">Toggle Filtering</button>
      <div id="grid1" ui-grid="gridOptions" class="grid"></div>
    </div>
  </file>
  <file name="main.css">
    .grid {
      width: 650px;
      height: 400px;
    }

    .header-filtered {
      color: blue;
    }
  </file>
  <file name="scenario.js">
    var gridTestUtils = require('../../test/e2e/gridTestUtils.spec.js');

    describe('first grid on the page, filtered by male by default', function() {
      gridTestUtils.firefoxReload();

      it('grid should have eight visible columns', function () {
        gridTestUtils.expectHeaderColumnCount( 'grid1', 8 );
      });

      it('filter on 4 columns, filter with greater than/less than on one, one with no filter, then one with one filter', function () {
        gridTestUtils.expectFilterBoxInColumn( 'grid1', 0, 1 );
        gridTestUtils.expectFilterSelectInColumn( 'grid1', 1, 1 );
        gridTestUtils.expectFilterBoxInColumn( 'grid1', 2, 0 );
        gridTestUtils.expectFilterBoxInColumn( 'grid1', 3, 1 );
        gridTestUtils.expectFilterBoxInColumn( 'grid1', 4, 1 );
        gridTestUtils.expectFilterBoxInColumn( 'grid1', 5, 2 );
        gridTestUtils.expectFilterBoxInColumn( 'grid1', 6, 1 );
      });

      it('third row should be Hatfield Hudson - will be Terry Clay if filtering broken', function () {
        gridTestUtils.expectCellValueMatch( 'grid1', 2, 0, 'Hatfield Hudson' );
      });

      it('cancel filter on gender column and on date column, should now see Bishop Carr in third row', function() {
        gridTestUtils.cancelFilterInColumn( 'grid1', 1 )
          .then(function () {
            return gridTestUtils.cancelFilterInColumn( 'grid1', 6 );
          })
          .then(function () {
            gridTestUtils.expectCellValueMatch( 'grid1', 2, 0, 'Bishop Carr' );
          });
      });

      it('filter on email column, should automatically do "ends with"', function() {
        gridTestUtils.cancelFilterInColumn( 'grid1', 1 )
          .then(function () {
            return gridTestUtils.cancelFilterInColumn( 'grid1', 6 );
          })
          .then(function () {
            return gridTestUtils.enterFilterInColumn( 'grid1', 3, 'digirang.com' );
          })
          .then(function () {
            gridTestUtils.expectRowCount( 'grid1', 2 );
          });
      });
    });
  </file>
</example>
