Files
angular.js/docs/content/tutorial/step_11.ngdoc
T
Georgios Kalpakas c2033d7ff0 docs(tutorial): update to use v1.5.x and best practices
This is a major re-structuring of the tutorial app's codebase, aiming at applying established best
practices (in terms of file naming/layout and code organization) and utilizing several new features
and enhancements (most notably components) introduced in recent versions of Angular (especially
v1.5).

Apart from the overall changes, two new chapters were introduced: one on components and one on code
organization.

--
In the process, several other things were (incidentally) taken care of, including:

* Dependencies were upgraded to latest versions.
* Animations were polished.
* Outdated links were updated.
* The app's base URL was changed to `/` (instead of `/app/`).

BTW, this has been tested with the following versions of Node (on Windows 10) and everything worked
fine:

* 0.11.16
* 4.2.6
* 4.4.2
* 5.10.0
* 6.2.0

--
This was inspired by (and loosely based on) #13834.
Again, mad props to @teropa for leading the way :)

--
**Note:**
The old version of the tutorial, that is compatible with Angular version 1.4 or older, has been
saved on the `pre-v1.5.0-snapshot` branch of
[angular-phonecat](https://github.com/angular/angular-phonecat). The `v1.4.x` version of the
tutorial should be pointed to that branch instead of `master`.

--
Related to angular/angular-phonecat#326.
Related to angular/angular-seed#341.

Closes #14416
2016-05-24 14:07:08 +03:00

177 lines
4.3 KiB
Plaintext

@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 Angular 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 Angular 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 Angular to enhance the phone details page further.
<ul doc-tutorial-nav="11"></ul>