上一課的例子中,我們的模型數據是硬編碼的,也就是說,我們的數據不是從服務器請求回來的。
這裡,我們先講解,如何從服務器獲取數據:
function PhoneListCtrl($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}
上一課的例子,我們只需要改寫這個控制器構造函數就行了。
$http向Web服務器發起一個HTTP GET請求,獲取phone/phones.json。AngularJS會自動檢測這個應答是什麼格式的,並且幫我們解析出來!
為了使用AngularJS的服務,你只需要在控制器的構造函數裡面傳入所需服務的名字。
當控制器構造的時候,AngularJS的依賴注入器會將這些服務注入到你的控制器中。
由於AngularJS是通過控制器構造函數的參數名字來推斷依賴服務名稱的。所以如果你要壓縮PhoneListCtrl控制器的JS代碼,它所有的參數也同時會被壓縮,這時候依賴注入系統就不能正確的識別出服務了。
為了克服壓縮引起的問題,只要在控制器函數裡面給$inject屬性賦值一個依賴服務標識符的數組,就像:
PhoneListCtrl.$inject = ['$scope', '$http'];
另一種方法也可以用來指定依賴列表並且避免壓縮問題——使用Javascript數組方式構造控制器:把要注入的服務放到一個字符串數組(代表依賴的名字)裡,數組最後一個元素是控制器的方法函數:
var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];
上面提到的兩種方法都能和AngularJS可注入的任何函數完美協作,要選哪一種方式完全取決於你們項目的編程風格,建議使用數組方式。
然後,我們為手機列表的手機數據項添加縮略圖以及鏈接:
[
{
...
"id": "motorola-defy-with-motoblur",
"imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg",
"name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
...
},
...
]
html改成這樣:
...
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
<a href="#/phones/{{phone.id}}" class="thumb">
<img ng-src="{{phone.imageUrl}}">
</a>
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
...
為每條記錄添加圖片,只需要使用ngSrc指令代替<img>的src屬性標簽就可以了。因為如果我們用一個正常src屬性來進行綁定(<img class="diagram" src="{{phone.imageUrl}}">),浏覽器會把AngularJS的{{ 表達式 }}標記直接進行字面解釋,這時會發起一個向非法url:http://localhost:8000/app/{{phone.imageUrl}}的請求,因為浏覽器載入頁面時,同時也會請求載入圖片。有了這個ngSrc指令,就會避免產生這種情況。
上面的應用只給我們的用戶提供了一個簡單的界面(一張所有手機的列表),並且所有的模板代碼位於index.html文件中。
最後,我們增加一個能夠顯示我們列表中每一部手機詳細信息的頁面。
為了增加詳細信息視圖,我們可以拓展index.html來同時包含兩個視圖的模板代碼,但是這樣會很快給我們帶來巨大的麻煩。相反,我們要把index.html模板轉變成“布局模板”。這是我們應用所有視圖的通用模板。其他的“局部布局模板”,根據當前的“路由”被填入,從而形成一個完整視圖展示給用戶。
AngularJS中的路由是通過$routeProvider來聲明的,它是$route服務的提供者。這項服務使得控制器、視圖模板與當前浏覽器的URL可以輕易集成。它允許我們使用浏覽器的歷史(回退或者前進導航)和書簽。
angular運行時,它會創建一個注入器,後面所有依賴注入的服務都會需要它。這個注入器自己並不知道$http和$route是干什麼的,注入器唯一的職責是載入指定的服務模塊,在這些模塊中注冊所有定義的服務提供者,並且當需要時給一個指定的函數注入服務。這些服務通過它們的提供者“懶惰式”(需要時才加載)實例化。
提供者提供服務實例並且對外提供API接口的對象,它可以被用來控制一個服務的創建和運行。對於$route服務來說,$routeProvider對外提供了API接口,通過API接口允許你為你的應用程序定義路由規則。
為了給我們的應用配置路由,我們需要給應用創建一個模塊。
angular.module('phonecat', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl}).
when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
otherwise({redirectTo: '/phones'});
}]);
我們把這個模塊定義為phonecat,並且通過使用config方法,我們把$routeProvider注入到我們的配置函數中,並且使用$routeProvider.when方法來定義我們的路由規則。
我們的路由規則定義如下:
(1)當URL 映射段為/phones時,手機列表視圖會被顯示出來。為了構造這個視圖,AngularJS會使用phone-list.html模板和PhoneListCtrl控制器。
(2)當URL 映射段為/phone/:phoneId時,手機詳細信息視圖被顯示出來。這裡:phoneId是URL的變量部分。為了構造手機詳細視圖,AngularJS會使用phone-detail.html模板和PhoneDetailCtrl控制器。
(3)otherwise({redirectTo: '/phones'})語句使得當浏覽器地址不能匹配我們任何一個路由規則時,觸發重定向到/phones。
我們重用之前創造過的PhoneListCtrl控制器,同時我們為手機詳細視圖添加一個新的PhoneDetailCtrl控制器。
為了讓我們新創建的模塊運行起來,我們需要在ngApp指令的值上指明模塊的名字:
<!doctype html>
<html lang="en" ng-app="phonecat">
...
</html>
新的PhoneDetailCtrl控制器:
function PhoneDetailCtrl($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}
注意到在第二條路由聲明中:phoneId參數的使用。所有以:符號聲明的變量(此處變量為phones)都會被提取,然後存放在$routeParams對象中。
$route服務通常和ngView指令一起使用。ngView指令的角色是為當前路由把對應的視圖模板載入到布局模板中。
<html lang="en" ng-app="phonecat">
<head>
...
<script src="lib/angular/angular.js"></script>
...
</head>
<body>
<div ng-view>
</div>
</body>
</html>
注意,我們把index.html模板裡面大部分代碼移除,我們只放置了一個<div>容器,這個<div>具有ng-view屬性。我們刪除掉的代碼現在被放置在phone-list.html模板中:
<div class="container-fluid">
<div class="row-fluid">
<div class="span2">
Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</div>
<div class="span10">
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
</div>
</div>
</div>
同時我們為手機詳細信息視圖添加一個占位模板。
TBD: detail view for {{phoneId}}
大家注意到我們上面的兩個模板中沒有添加PhoneListCtrl或PhoneDetailCtrl控制器屬性!
這樣就實現了一個基於angular的多視圖的應用程序。
AngularJS權威教程 清晰PDF版 http://www.linuxidc.com/Linux/2015-01/111429.htm
希望你喜歡,並分享我的工作~帶你走近AngularJS系列:
如何在 AngularJS 中對控制器進行單元測試 http://www.linuxidc.com/Linux/2013-12/94166.htm
在 AngularJS 應用中通過 JSON 文件來設置狀態 http://www.linuxidc.com/Linux/2014-07/104083.htm
AngularJS 之 Factory vs Service vs Provider http://www.linuxidc.com/Linux/2014-05/101475.htm
AngularJS —— 使用 ngResource、RESTful APIs 和 Spring MVC 框架提交數據 http://www.linuxidc.com/Linux/2014-07/104402.htm
AngularJS 的詳細介紹:請點這裡
AngularJS 的下載地址:請點這裡