Files
angular.js/docs/content/tutorial/step_10.ngdoc
T
Georgios Kalpakas b5dbc9834a 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 15:44:19 +03:00

215 lines
5.0 KiB
Plaintext

@ngdoc tutorial
@name 10 - More Templating
@step 10
@description
<ul doc-tutorial-nav="10"></ul>
In this step, we will implement the phone details view, which is displayed when a user clicks on a
phone in the phone list.
* When you click on a phone on the list, the phone details page with phone-specific information is
displayed.
To implement the phone details view we are going to use {@link ng.$http $http} to fetch our data,
and then flesh out the `phoneDetail` component's template.
<div doc-tutorial-reset="10"></div>
## Data
In addition to `phones.json`, the `app/phones/` directory also contains one JSON file for each
phone:
<br />
**`app/phones/nexus-s.json`:** (sample snippet)
```json
{
"additionalFeatures": "Contour Display, Near Field Communications (NFC), ...",
"android": {
"os": "Android 2.3",
"ui": "Android"
},
...
"images": [
"img/phones/nexus-s.0.jpg",
"img/phones/nexus-s.1.jpg",
"img/phones/nexus-s.2.jpg",
"img/phones/nexus-s.3.jpg"
],
"storage": {
"flash": "16384MB",
"ram": "512MB"
}
}
```
Each of these files describes various properties of the phone using the same data structure. We will
show this data in the phone details view.
## Component Controller
We will expand the `phoneDetail` component's controller by using the `$http` service to fetch the
appropriate JSON files. This works the same way as the `phoneList` component's controller.
<br />
**`app/phone-detail/phone-detail.component.js`:**
```js
angular.
module('phoneDetail').
component('phoneDetail', {
templateUrl: 'phone-detail/phone-detail.template.html',
controller: ['$http', '$routeParams',
function PhoneDetailController($http, $routeParams) {
var self = this;
$http.get('phones/' + $routeParams.phoneId + '.json').then(function(response) {
self.phone = response.data;
});
}
]
});
```
To construct the URL for the HTTP request, we use `$routeParams.phoneId`, which is extracted from
the current route by the `$route` service.
## Component Template
The inline, TBD placeholder template has been replaced with a full blown external template,
including lists and bindings that comprise the phone details. Note how we use the Angular
`{{expression}}` markup and `ngRepeat` to project phone data from our model into the view.
<br />
**`app/phone-detail/phone-detail.template.html`:**
```html
<img ng-src="{{$ctrl.phone.images[0]}}" class="phone" />
<h1>{{$ctrl.phone.name}}</h1>
<p>{{$ctrl.phone.description}}</p>
<ul class="phone-thumbs">
<li ng-repeat="img in $ctrl.phone.images">
<img ng-src="{{img}}" />
</li>
</ul>
<ul class="specs">
<li>
<span>Availability and Networks</span>
<dl>
<dt>Availability</dt>
<dd ng-repeat="availability in $ctrl.phone.availability">{{availability}}</dd>
</dl>
</li>
...
<li>
<span>Additional Features</span>
<dd>{{$ctrl.phone.additionalFeatures}}</dd>
</li>
</ul>
```
<img class="diagram" src="img/tutorial/tutorial_10.png">
# Testing
We wrote a new unit test that is similar to the one we wrote for the `phoneList` component's
controller in {@link step_07#testing step 7}.
<br />
**`app/phone-detail/phone-detail.component.spec.js`:**
```js
describe('phoneDetail', function() {
// Load the module that contains the `phoneDetail` component before each test
beforeEach(module('phoneDetail'));
// Test the controller
describe('PhoneDetailController', function() {
var $httpBackend, ctrl;
beforeEach(inject(function($componentController, _$httpBackend_, $routeParams) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('phones/xyz.json').respond({name: 'phone xyz'});
$routeParams.phoneId = 'xyz';
ctrl = $componentController('phoneDetail');
}));
it('should fetch the phone details', function() {
expect(ctrl.phone).toBeUndefined();
$httpBackend.flush();
expect(ctrl.phone).toEqual({name: 'phone xyz'});
});
});
});
```
You should now see the following output in the Karma tab:
```
Chrome 49.0: Executed 3 of 3 SUCCESS (0.159 secs / 0.136 secs)
```
We also added a new E2E test that navigates to the 'Nexus S' details page and verifies that the
heading on the page is "Nexus S".
<br />
**`e2e-tests/scenarios.js`**
```js
...
describe('View: Phone detail', function() {
beforeEach(function() {
browser.get('index.html#!/phones/nexus-s');
});
it('should display the `nexus-s` page', function() {
expect(element(by.binding('$ctrl.phone.name')).getText()).toBe('Nexus S');
});
});
...
```
You can run the tests with `npm run protractor`.
# Experiments
<div></div>
* Using [Protractor's API][protractor-docs], write a test that verifies that we display 4 thumbnail
images on the 'Nexus S' details page.
# Summary
Now that the phone details view is in place, proceed to {@link step_11 step 11} to learn how to
write your own custom display filter.
<ul doc-tutorial-nav="10"></ul>
[protractor-docs]: https://angular.github.io/protractor/#/api