在這一步,你將實現手機詳細信息視圖,這個視圖會在用戶點擊手機列表中的一部手機時被顯示出來。
請重置工作目錄:
~~~
git checkout -f step-8
~~~
現在當你點擊列表中的一部手機之后,這部手機的詳細信息頁面就會被顯示出來。
為了實現手機詳細信息視圖我們將會使用[$http](http://code.angularjs.org/1.1.0/docs/api/ng.$http)來獲取數據,同時我們也要增添一個`phone-detail.html`視圖模板。
步驟7和步驟8之間最重要的不同在下面列出。你可以在[GitHub](https://github.com/angular/angular-phonecat/compare/step-7...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"
}
}
~~~
這些文件中的每一個都用相同的數據結構描述了一部手機的不同屬性。我們會在手機詳細信息視圖中顯示這些數據。
## 控制器
我們使用`$http`服務獲取數據,以此來拓展我們的`PhoneListCtrl`。這和之前的手機列表控制器的工作方式是一樣的。
app/js/controllers.js
~~~
function PhoneDetailCtrl($scope, $routeParams, $http) {
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
$scope.phone = data;
});
}
//PhoneDetailCtrl.$inject = ['$scope', '$routeParams', '$http'];
~~~
為了構造HTTP請求的URL,我們需要`$route`服務提供的當前路由中抽取`$routeParams.phoneId`。
## 模板
phone-detail.html文件中原有的TBD占位行已經被列表和構成手機詳細信息的綁定替換掉了。注意到,這里我們使用AngularJS的`{{表達式}}`標記和`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>
~~~
## 測試
我們來寫一個新的單元測試,這個測試和我們在步驟5中為`PhoneListCtrl`寫的那個很像。
test/unit/controllersSpec.js
~~~
...
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'});
});
});
...
~~~
執行`./scripts/test.sh`腳本來執行測試,你應該會看到如下輸出:
~~~
Chrome: Runner reset.
...
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
~~~
同時,我們也添加一個端到端測試,指向Nexus S手機詳細信息頁面并且驗證頁面的頭部是“Nexus S”。
test/e2e/scenarios.js
~~~
...
describe('Phone detail view', function() {
beforeEach(function() {
browser().navigateTo('../../app/index.html#/phones/nexus-s');
});
it('should display nexus-s page', function() {
expect(binding('phone.name')).toBe('Nexus S');
});
});
...
~~~
你現在可以刷新你的瀏覽器,然后重新跑一遍端到端測試,或者你可以在[AngularJS的服務器](http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html)上運行一下。
## 練習
使用[AngularJS端到端測試API](http://code.angularjs.org/1.1.0/docs/guide/dev_guide.e2e-testing)寫一個測試,用它來驗證我們在Nexus S詳細信息頁面顯示的四個縮略圖。
## 總結
現在手機詳細頁面已經就緒了,在[步驟9](a00c)中我們將學習如何寫一個顯示過濾器。