標籤:
上一課,大家知道,手機詳細模板我們沒有寫出來,使用的是一個佔位模板。
這一課,我們先實現手機詳細資料檢視,這個視圖會在使用者點擊手機列表中的一部手機時被顯示出來。
為了實現手機詳細資料檢視,我們將會使用$http來擷取資料。
以下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
服務擷取資料,以此來拓展我們的PhoneDetailCtrl控制器。這和之前手機列表控制器的工作方式是一樣的。
function PhoneDetailCtrl($scope, $routeParams, $http) {
$http.get(‘phones/‘ + $routeParams.phoneId + ‘.json‘).success(function(data) {
$scope.phone = data;
});
}
phone-detail.html檔案中原有的TBD佔位行已經被手機詳細資料替換掉了。注意到,這裡我們使用AngularJS的{{運算式}}標記和ngRepeat來在視圖中渲染資料模型。
<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>
然後,我們在程式中建立自己的過濾器。
為了建立一個新的過濾器,我們先建立一個phonecatFilters
模組,並且將定製的過濾器checkmark註冊給這個模組。
angular.module(‘phonecatFilters‘, []).filter(‘checkmark‘, function() {
return function(input) {
return input ? ‘\u2713‘ : ‘\u2718‘;
};
});
我們的過濾器命名為checkmark。它的輸入要麼是true,要麼是false,並且我們返回兩個表示true或false的unicode字元(\u2713和\u2718)。
現在我們的過濾器準備好了,我們需要將我們的phonecatFilters
模組作為一個依賴,註冊到我們的主模組phonecat
上。
...
angular.module(‘phonecat‘, [‘phonecatFilters‘]).
...
在AngularJS模板中使用過濾器的文法是:{{ expression | filter }}
因此,我們把過濾器應用到手機詳細資料模板中是這樣寫的:
... <dl> <dt>Infrared</dt> <dd>{{phone.connectivity.infrared | checkmark}}</dd> <dt>GPS</dt> <dd>{{phone.connectivity.gps | checkmark}}</dd> </dl>...
這樣就實現了這樣的一個功能:手機詳細頁面原來是顯示“true”或者“false”來說明某個手機是否具有特定的特性。現在我們使用一個定製的過濾器來把那些文本串圖形化:√作為“true”;以及×作為“false”。也就說,在手機詳細頁面,true變成了√,false變成了×。
最後,我們讓手機詳細資料頁面上的手機圖片可以點擊。
手機詳細資料檢視展示了一幅當前手機的大號圖片,以及幾個小一點的縮圖。我們實現當使用者點擊縮圖就能把那張大的替換成使用者點擊的那張圖片。
...function PhoneDetailCtrl($scope, $routeParams, $http) { $http.get(‘phones/‘ + $routeParams.phoneId + ‘.json‘).success(function(data) { $scope.phone = data; $scope.mainImageUrl = data.images[0]; }); $scope.setImage = function(imageUrl) { $scope.mainImageUrl = imageUrl; }}
在PhoneDetailCtrl控制器中,我們建立了mainImageUrl模型屬性,並且把它的預設值設為第一個手機圖片的URL。
<img ng-src="{{mainImageUrl}}" class="phone">...<ul class="phone-thumbs"> <li ng-repeat="img in phone.images"> <img ng-src="{{img}}" ng-click="setImage(img)"> </li></ul>...
我們把大圖片的ngSrc
指令綁定到mainImageUrl
屬性上。
同時我們註冊一個ngClick處理器到縮圖上。當一個使用者點擊縮圖的任意一個時,這個處理器會使用setImage事件處理函數來把mainImageUrl屬性設定成選定縮圖的URL。
這樣就輕易的實現了上面的需求。
對我們應用程式所做的最後一個改進是擷取資料的方式。我們可以用一種更簡單的方式來發送XHR請求,而不用去關心更底層的$http服務。
angular.module(‘phonecatServices‘, [‘ngResource‘]). factory(‘Phone‘, function($resource){ return $resource(‘phones/:phoneId.json‘, {}, { query: {method:‘GET‘, params:{phoneId:‘phones‘}, isArray:true} }); });
我們使用模組的API,通過它的Factory 方法註冊了一個定製服務Phone。我們傳入服務的名字Phone和工廠函數。工廠函數和控制器建構函式差不多,它們都通過函數的參數聲明,來依賴服務。Phone服務聲明了它依賴於$resource服務。
我們需要在頁面上載入angularjs-resource.js這個檔案,它包含了ngResource
模組以及其中的$resource
服務:
...
<script src="lib/angular/angular-resource.js"></script>
...
$resource服務,用短短的幾行代碼就可以建立一個RESTful用戶端。我們的應用程式使用這個用戶端來代替底層的$http服務。AngularJS的$resource相比於$http更加適合於與RESTful資料來源互動。
然後,我們需要把phonecatServices
添加到phonecat
的依賴數組裡。
...
angular.module(‘phonecat‘, [‘phonecatFilters‘, ‘phonecatServices‘]).
...
通過重構底層的$http服務,把它放在一個新的服務Phone中,我們可以大大簡化子控制器(PhoneListCtrl和PhoneDetailCtrl)。
...function PhoneListCtrl($scope, Phone) { $scope.phones = Phone.query(); $scope.orderProp = ‘age‘;}//PhoneListCtrl.$inject = [‘$scope‘, ‘Phone‘];function PhoneDetailCtrl($scope, $routeParams, Phone) { $scope.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) { $scope.mainImageUrl = phone.images[0]; }); $scope.setImage = function(imageUrl) { $scope.mainImageUrl = imageUrl; }}//PhoneDetailCtrl.$inject = [‘$scope‘, ‘$routeParams‘, ‘Phone‘];
注意到,在PhoneListCtrl裡我們把:
$http.get(‘phones/phones.json‘).success(function(data) {
$scope.phones = data;
});
換成了:
$scope.phones = Phone.query();
我們通過這條簡單的語句來查詢所有的手機。
另一個非常需要注意的是,在上面的代碼裡面,PhoneListCtrl控制器調用Phone服務的方法時,我們並沒有傳遞任何回呼函數。儘管這看起來是同步返回的,其實根本就不是。同步返回的是一個“future”——一個對象,當XHR響應完成返回的時候會填充資料。鑒於AngularJS的資料繫結,我們可以使用future,並且把它綁定到我們的模板上。然後,當資料到達時,我們的視圖會自動更新。
但有的時候,單單依賴future對象和資料繫結不足以滿足我們的需求,所以在這些情況下,我們需要添加一個回呼函數來處理伺服器的響應。PhoneDetailCtrl控制器通過在一個回呼函數中設定mainImageUrl就是一個解釋。
通過這四篇對angular.js的入門講解,我相信大家都angular有了初步的認識,接下來,我們將深入講解angular.js。
加油!
AngularJS入門講解4:多視圖,事件綁定,$resource服務講解