本章我们将把手机的详情页做详细一点。改动很简单:
- 当点击列表页中的某个手机时,手机详情页将被展示。
另外比较有趣的是,这次详情页的数据获取我们将借助$http
服务来完成。
使用git迁出step-8分支就是该章对应的实例代码:
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格式文件。
这和列表页获取手机列表控制器是类似的。
app/js/controllers.js
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;
});
}]);
我们使用由$route
服务从当前路由地址中抽取的¥routeParams.phoneId
变量来构建不同手机的不通HTTP请求的URL地址。
模版
我们把之前的TBD占位行替换成了手机详情内容。注意我们是在哪里使用{{expression}}
标记和ngRepeat
指令来完成模型到视图的数据传递的。
app/partials/phone-detail.html
<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>
测试
我们写了一个和第七章中为PhoneListCtrl
控制器写的差不多的单元测试:
test/unit/controllersSpec.js
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)
我们还写了一个端到端测试来测试详情页的Heading是不是“Nexus S”。
test/e2e/scenarios.js
...
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
,写一个测试用例,用来验证Nexus详情页4张照片是否显示正确。(注解:觉得复杂就别做了。没啥。)
总结
下一章我们将学习如何编写自己的过滤器。