Improve this Doc

In this step, we will implement the phone details view, which is displayed when a user clicks on a phone in the phone list.

To implement the phone details view we are going to use $http to fetch our data, and then flesh out the phoneDetail component's template.

Data

In addition to phones.json, the app/phones/ directory also contains one JSON file for each phone:


app/phones/nexus-s.json: (sample snippet)

{
  "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.


app/phone-detail/phone-detail.component.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 AngularJS {{expression}} markup and ngRepeat to project phone data from our model into the view.


app/phone-detail/phone-detail.template.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>

Testing

We wrote a new unit test that is similar to the one we wrote for the phoneList component's controller in step 7.


app/phone-detail/phone-detail.component.spec.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".


e2e-tests/scenarios.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

Summary

Now that the phone details view is in place, proceed to step 11 to learn how to write your own custom display filter.