Еще раз о шаблонизации в AngularJS

На этом шаге мы реализуем представление отображающее детали телефона, которые отображаются, когда пользователь кликает на телефоне из списка.

Мы будем получать данные с помощью $http и наполнять ими шаблон представления phone-detail.html.

Переключить проект на состояние соответствующее шагу:

git checkout -f step-8

На этом шаге будут внесены такие изменения.


Данные

В дополнении к phones.json папка app/phones/ также содержит JSON файл для каждого телефона.
app/phones/nexus-s.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"
  }
}

Каждый из этих файлов описывает различные свойства телефонов. Эти свойства будут отображаться на странице с деталями устройства.

Контроллер

Мы расширим код контроллера PhoneDetailCtrl с помощью сервиса $http, который задействуем для получения JSON-файлов.
var phonecatControllers = angular.module('phonecatControllers',[]);

phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http',
  function($scope, $routeParams, $http) {
    $http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
      $scope.phone = data;
    });
  }]);

Для генерации URL для HTTP-запроса, мы используем $routeParams.phoneId, извлекаемый из текущего маршрута с помощью сервиса $route.

Представление

Placeholder TBD надо заменить на списки и биндинги заключающие в себе детали телефона.
<img ng-src="{{phone.images[0]}}" class="phone">

<h1>{{phone.name}}</h1>

<p>{{phone.description}}</p>

<ul class="phone-thumbs">
  <li ng-repeat="img in 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 phone.availability">{{availability}}</dd>
    </dl>
  </li>
    ...
  <li>
    <span>Additional Features</span>
    <dd>{{phone.additionalFeatures}}</dd>
  </li>
</ul>


Тестирование

Напишем новый модульный тест:
  beforeEach(module('phonecatApp'));

  ...

  describe('PhoneDetailCtrl', function(){
    var scope, $httpBackend, ctrl;

    beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
      $httpBackend = _$httpBackend_;
      $httpBackend.expectGET('phones/xyz.json').respond({name:'phone xyz'});

      $routeParams.phoneId = 'xyz';
      scope = $rootScope.$new();
      ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
    }));


    it('should fetch phone detail', function() {
      expect(scope.phone).toBeUndefined();
      $httpBackend.flush();

      expect(scope.phone).toEqual({name:'phone xyz'});
    });
  });
...

Вывод Karma должен быть следующим:
Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)

Также добавим новый end-to-end тест, который переходит на страницу деталей телефона Nexus S и проверяет, что заголовком страницы является строка "Nexus S".

...
  describe('Phone detail view', function() {

    beforeEach(function() {
      browser.get('app/index.html#/phones/nexus-s');
    });


    it('should display nexus-s page', function() {
      expect(element(by.binding('phone.name')).getText()).toBe('Nexus S');
    });
  });
...

Теперь можно перезапустить тесты npm run protractor

Используя Protractor API, можно написать тест, который верифицирует отображение 4 миниатюр на странице с деталями телефона Nexus S.