angular/angular.js

View on GitHub
docs/content/tutorial/step_11.ngdoc

Summary

Maintainability
Test Coverage
@ngdoc tutorial
@name 11 - Custom Filters
@step 11
@description

<ul doc-tutorial-nav="11"></ul>


In this step you will learn how to create your own custom display filter.

* In the previous step, the details page displayed either "true" or "false" to indicate whether
  certain phone features were present or not. In this step, we are using a custom filter to convert
  those text strings into glyphs: ✓ for "true", and ✘ for "false".

Let's see what the filter code looks like.


<div doc-tutorial-reset="11"></div>


## The `checkmark` Filter

Since this filter is generic (i.e. it is not specific to any view or component), we are going to
register it in a `core` module, which contains "application-wide" features.

<br />
**`app/core/core.module.js`:**

```js
angular.module('core', []);
```

<br />
**`app/core/checkmark/checkmark.filter.js`:**

```js
  angular.
    module('core').
    filter('checkmark', function() {
      return function(input) {
        return input ? '\u2713' : '\u2718';
      };
    });
```

<div class="alert alert-info">
  As you may have noticed, we (unsurprisingly) gave our file a `.filter` suffix.
</div>

The name of our filter is "checkmark". The `input` evaluates to either `true` or `false`, and we
return one of the two unicode characters we have chosen to represent true (`\u2713` -> ✓) and false
(`\u2718` -> ✘).

Now that our filter is ready, we need to register the `core` module as a dependency of our main
`phonecatApp` module.

<br />
**`app/app.module.js`:**

```js
angular.module('phonecatApp', [
  ...
  'core',
  ...
]);
```


## Templates

Since we have created two new files (**core.module.js**, **checkmark.filter.js**), we need to
include them in our layout template.

<br />
**`app/index.html`:**

```html
    ...
    <script src="core/core.module.js"></script>
    <script src="core/checkmark/checkmark.filter.js"></script>
    ...
```

The syntax for using filters in AngularJS templates is as follows:

```
{{expression | filter}}
```

Let's employ the filter in the phone details template:

<br />
**`app/phone-detail/phone-detail.template.html`:**

```html
    ...
    <dl>
      <dt>Infrared</dt>
      <dd>{{$ctrl.phone.connectivity.infrared | checkmark}}</dd>
      <dt>GPS</dt>
      <dd>{{$ctrl.phone.connectivity.gps | checkmark}}</dd>
    </dl>
    ...
```


## Testing

Filters, like any other code, should be tested. Luckily, these tests are very easy to write.

<br />
**`app/core/checkmark/checkmark.filter.spec.js`:**

```js
describe('checkmark', function() {

  beforeEach(module('core'));

  it('should convert boolean values to unicode checkmark or cross',
    inject(function(checkmarkFilter) {
      expect(checkmarkFilter(true)).toBe('\u2713');
      expect(checkmarkFilter(false)).toBe('\u2718');
    })
  );

});
```

The call to `beforeEach(module('core'))` loads the `core` module (which contains the `checkmark`
filter) into the injector, before every test.

Note that we call the helper function `inject(function(checkmarkFilter) {...})`, to get access to
the filter that we want to test. See also {@link angular.mock.inject angular.mock.inject()}.

<div class="alert alert-info">
  When injecting a filter, we need to suffix the filter name with 'Filter'. For example, our
  `checkmark` filter is injected as `checkmarkFilter`.
  See the [Filters](guide/filter#using-filters-in-controllers-services-and-directives) section of
  the Developer Guide for more info.
</div>

You should now see the following output in the Karma tab:

```
Chrome 49.0: Executed 4 of 4 SUCCESS (0.091 secs / 0.075 secs)
```


## Experiments

<div></div>

* Let's experiment with some of the {@link api/ng/filter built-in AngularJS filters}.
  Add the following bindings to `index.html`:

  * `{{'lower cap string' | uppercase}}`
  * `{{{foo: 'bar', baz: 42} | json}}`
  * `{{1459461289000 | date}}`
  * `{{1459461289000 | date:'MM/dd/yyyy @ h:mma'}}`


* We can also create a model with an input element, and combine it with a filtered binding.
  Add the following to `index.html`:

  ```html
  <input ng-model="userInput" /> Uppercased: {{userInput | uppercase}}
  ```


## Summary

Now that we have learned how to write and test a custom filter, let's go to {@link step_12 step 12}
to learn how we can use AngularJS to enhance the phone details page further.


<ul doc-tutorial-nav="11"></ul>