步骤8——更多模板

这一步我们会实现手机详细说明视图,它将在我们点击手机列表中的手机链接后显示。 *当点击手机列表中一个手机的链接,指定手机的详细说明页面将显示出对应手机的详细信息。

工作区切换到步骤8

直接用浏览器访问步骤8在线演示

大多数的重要改变都会列在下面,不过你也可以在GitHub看到完整的差异。

数据

添加phones.json,在app/phones/目录中也包括每个手机的json文件: app/phones/nexus-s.json:(一个简单的例子)

  1. {
  2. "additionalFeatures": "Contour Display, Near Field Communications (NFC),...",
  3. "android": {
  4. "os": "Android 2.3",
  5. "ui": "Android"
  6. },
  7. ...
  8. "images": [
  9. "img/phones/nexus-s.0.jpg",
  10. "img/phones/nexus-s.1.jpg",
  11. "img/phones/nexus-s.2.jpg",
  12. "img/phones/nexus-s.3.jpg"
  13. ],
  14. "storage": {
  15. "flash": "16384MB",
  16. "ram": "512MB"
  17. }
  18. }

每个文件都有相同的属性数据结构,我们会把这些数据显示在手机详细说明视图中。

控制器

我们使用$http服务请求json文件功能来增强PhoneDetailCtrl。它们采用手机列表控制器相同的方式工作。 app/js/controllers.js:

  1. var phonecatControllers = angular.module('phonecatControllers',[]);
  2. phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http',
  3. function($scope, $routeParams, $http) {
  4. $http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
  5. $scope.phone = data;
  6. });
  7. }]);

为了构建HTTP的URL请求,我们从定义在$route功能中的当前路由中扩展出$routeParams.phoneId

模板

前面用占位符粗略定义的模板被手机详细说明各部分的列表和数据绑定替换。注意我们使用了Angular{{表达式}}标签和ngRepeat来从我们数据模型中提取手机数据供显示。 app/partials/phone-detail.html:

  1. <img ng-src="{{phone.images[0]}}" class="phone">
  2. <h1>{{phone.name}}</h1>
  3. <p>{{phone.description}}</p>
  4. <ul class="phone-thumbs">
  5. <li ng-repeat="img in phone.images">
  6. <img ng-src="{{img}}">
  7. </li>
  8. </ul>
  9. <ul class="specs">
  10. <li>
  11. <span>Availability and Networks</span>
  12. <dl>
  13. <dt>Availability</dt>
  14. <dd ng-repeat="availability in phone.availability">{{availability}}</dd>
  15. </dl>
  16. </li>
  17. ...
  18. <li>
  19. <span>Additional Features</span>
  20. <dd>{{phone.additionalFeatures}}</dd>
  21. </li>
  22. </ul>

测试

我们写了一个类似我们在步骤5中PhoneListCtrl控制器的新单元测试。 test/unit/controllersSpec.js:

  1. beforeEach(module('phonecatApp'));
  2. ...
  3. describe('PhoneDetailCtrl', function(){
  4. var scope, $httpBackend, ctrl;
  5. beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
  6. $httpBackend = _$httpBackend_;
  7. $httpBackend.expectGET('phones/xyz.json').respond({name:'phone xyz'});
  8. $routeParams.phoneId = 'xyz';
  9. scope = $rootScope.$new();
  10. ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
  11. }));
  12. it('should fetch phone detail', function() {
  13. expect(scope.phone).toBeUndefined();
  14. $httpBackend.flush();
  15. expect(scope.phone).toEqual({name:'phone xyz'});
  16. });
  17. });
  18. ...

你应该可以看到类似下面的Karma输出:

  1. Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)

我们也添加一个新的端到端测试导航到Nexus S的详细说明页面验证页面头部是否有”Nexus S”。 test/e2e/scenarios.js:

  1. ...
  2. describe('Phone detail view', function() {
  3. beforeEach(function() {
  4. browser.get('app/index.html#/phones/nexus-s');
  5. });
  6. it('should display nexus-s page', function() {
  7. expect(element(by.binding('phone.name')).getText()).toBe('Nexus S');
  8. });
  9. });
  10. ...

你现在可以运行npm run protractor来运行端到端测试了。

尝试

使用Protractor API,写一个测试在Nexus S详细说明页面会显示4个缩略图的端到端测试项目。

小结

现在,我们的手机详细说明视图也已经建立好了,进入步骤9,学习如何写自定义的显示过滤器。