七步從Angular.JS菜鳥到專家(3):數(shù)據(jù)綁定和AJAX
這是"AngularJS - 七步從菜鳥到專家"系列的第三篇。
在***篇,我們展示了如何開始搭建一個AngularaJS應(yīng)用。第二篇我們討論了scope和 $scope 的功能。
通過這整個系列的教程,我們會開發(fā)一個NPR(美國全國公共廣播電臺)廣播的音頻播放器,它能顯示Morning Edition節(jié)目里現(xiàn)在播出的***故事,并在我們的瀏覽器里播放。完成版的Demo可以看這里。
第三部分 數(shù)據(jù)綁定
通過把一個文本輸入框綁定到person.name屬性上,就能把我們的應(yīng)用變得更有趣一點(diǎn)。這一步建立起了文本輸入框跟頁面的雙向綁定。
在這個語境里“雙向”意味著如果view改變了屬性值,model就會“看到”這個改變,而如果model改變了屬性值,view也同樣會“看到”這個改變。Angular.js 為你自動搭建好了這個機(jī)制。如果你好奇這具體是怎么實(shí)現(xiàn)的,請看我們之后推出的一篇文章,其中深入討論了digest_loop 的運(yùn)作。
要建立這個綁定,我們在文本輸入框上使用ng-model 指令屬性,像這樣:
- <div ng-controller="MyController">
- <input type="text" ng-model="person.name" placeholder="Enter your name" />
- <h5>Hello {{ person.name }}</h5>
- </div>
現(xiàn)在我們建立好了一個數(shù)據(jù)綁定(沒錯,就這么容易),來看看view怎么改變model吧:
試試看:
當(dāng)你在文本框里輸入時,下面的名字也自動隨之改變,這就展現(xiàn)了我們數(shù)據(jù)綁定的一個方向:從view到model。我們也可以在我們的(客戶端)后臺改變model,看這個改變自動在前端體現(xiàn)出來。要展示這一過程,讓我們在 MyController 的model里寫一個計(jì)時器函數(shù), 更新 $scope 上的一個數(shù)據(jù)。下面的代碼里,我們就來創(chuàng)建這個計(jì)時器函數(shù),它會在每秒計(jì)時(像鐘表那樣),并更新 $scope 上的clock變量數(shù)據(jù):
- app.controller('MyController', function($scope) { $scope.person = { name: "Ari Lerner" }; var updateClock = function() { $scope.clock = new Date(); }; var timer = setInterval(function() { $scope.$apply(updateClock); }, 1000); updateClock();});
可以看到,當(dāng)我們改變modelclock變量的數(shù)據(jù),view會自動更新來反映此變化。用大括號我們就可以很簡單地讓clock變量的值顯示在view里:
- <div ng-controller="MyController">
- <h5>{{ clock }}</h5>
- </div>
請看:
{{ clock }}
互動
前面我們把數(shù)據(jù)綁定在了文本輸入框上。請注意, 數(shù)據(jù)綁定并非只限于數(shù)據(jù),我們還可以利用綁定調(diào)用 $scope 中的函數(shù)(這一點(diǎn)之前已經(jīng)提到過)。
對按鈕、鏈接或任何其他的DOM元素,我們都可以用另一個指令屬性來實(shí)現(xiàn)綁定:ng-click 。這個 ng-click 指令將DOM元素的鼠標(biāo)點(diǎn)擊事件(即 mousedown 瀏覽器事件)綁定到一個方法上,當(dāng)瀏覽器在該DOM元素上鼠標(biāo)觸發(fā)點(diǎn)擊事件時,此被綁定的方法就被調(diào)用。跟上一個例子相似,這個綁定的代碼如下:
- <div ng-controller="DemoController">
- <h4>The simplest adding machine ever</h4>
- <button ng-click="add(1)" class="button">Add</button>
- <button ng-click="subtract(1)" class="button">Subtract</button>
- <h4>Current count: {{ counter }}</h4>
- </div>
不論是按鈕還是鏈接都會被綁定到包含它們的DOM元素的controller所有的 $scope 對象上,當(dāng)它們被鼠標(biāo)點(diǎn)擊,Angular就會調(diào)用相應(yīng)的方法。注意當(dāng)我們告訴Angular要調(diào)用什么方法時,我們將方法名寫進(jìn)帶引號的字符串里。
- app.controller('DemoController', function($scope) {
- $scope.counter = 0;
- $scope.add = function(amount) { $scope.counter += amount; };
- $scope.subtract = function(amount) { $scope.counter -= amount; };
- });
請看:
myApp中的數(shù)據(jù)綁定和AJAX
互動
在上一篇的例子中,我們對view的一個按鈕進(jìn)行了剛才學(xué)到的數(shù)據(jù)綁定,給play按鈕綁定了 PlayerController 的play方法(同樣的,還給stop按鈕綁定了stop方法)。
AJAX
在上一篇教程里,我們引用的是一個存儲在本地的音頻文件,它給我們的是一個靜態(tài)的NPR文件,而不是一個動態(tài)的NPR feed。在我們的NPR應(yīng)用里,我們將用$http 來填充我們可播放的新聞文件的列表。Angular.js原生支持AJAX,由此我們就獲得了與一個或多個服務(wù)器來回發(fā)送請求的能力。這個能力對我們要創(chuàng)建的這種客戶端應(yīng)用來說是至關(guān)重要的,因?yàn)檫@種應(yīng)用需要跟服務(wù)器交流,獲取和更新數(shù)據(jù)。Angular.js通過一個服務(wù)來支持AJAX(在之后的章節(jié)我們會討論這個服務(wù)),這個服務(wù)就叫做 $http 服務(wù)。所有Angular.js的核心服務(wù)都用 $ 前綴,這點(diǎn)在之前的 $scope 服務(wù)里我們已經(jīng)見過了。這個 $http 服務(wù)極其靈活,給了我們很多種方式來調(diào)用AJAX服務(wù)。為保證本教程簡單易懂,我們專注于最簡單的方式。在以后更高級的章節(jié)里我們會深入介紹 $http 服務(wù)。在深入過多細(xì)節(jié)之前,讓我們先來用 $http 服務(wù)創(chuàng)建一個請求:
- $http({ method: 'JSONP', url: 'http://api.openbeerdatabase.com/v1/beers.json?callback=JSON_CALLBACK'}).success(function(data, status, headers, config) { // data contains the response // status is the HTTP status // headers is the header getter function // config is the object that was used to create the HTTP request}).error(function(data, status, headers, config) {});
#p#
試試看:
$http 服務(wù)是Angular.js的核心服務(wù)之一,它幫助我們通過XMLHttpRequest對象或JSONP與遠(yuǎn)程HTTP服務(wù)進(jìn)行交流。
注意, 像上面例子中那樣,原封不動加上以下字符串 callback=JSON_CALLBACK ,Angular.js就會負(fù)責(zé)為你處理JSONP請求,將 JSON_CALLBACK 替換成一個合適的回調(diào)函數(shù)。
$http 服務(wù)是這樣一個函數(shù):它接受一個設(shè)置對象,其中指定了如何創(chuàng)建HTTP請求;它將返回一個承諾(*參考JavaScript異步編程的promise模式),其中提供兩個方法: success方法和error方法。
要取得可播放的音頻文件列表,讓我們向NPR的API發(fā)送一個請求。首先,你需要倒NPR注冊以取得一個API key。到它們的網(wǎng)站 http://www.npr.org/templates/reg/ 去。(作者在這里用Angular.js做了一個用iFrame加載的NPR注冊表單,見下圖,或者直接前往英文原文查看)。
記下你的API key,我們馬上就會用到它?,F(xiàn)在我們要設(shè)置我們的PlayController 來調(diào)用 $http 服務(wù),取回音頻文件。
像我們剛才做的那樣,讓我們調(diào)用 $http 服務(wù)來創(chuàng)建一個請求,這一次是為了取得所有音頻文件。我們想讓這個服務(wù)在controller實(shí)例化時啟動,所以我們只需要把這個方法直接放在controller函數(shù)里(這個函數(shù)在controller被創(chuàng)建時就會被調(diào)用),像這樣:
- var apiKey = 'YOUR_KEY',
- nprUrl = 'http://api.npr.org/query?id=61&fields=relatedLink,title,byline,text,audio,image,pullQuote,all&output=JSON';
- app.controller('PlayerController', function($scope, $http) {
- // Hidden our previous section's content
- // construct our http request
- $http({
- method: 'JSONP',
- url: nprUrl + '&apiKey=' + apiKey + '&callback=JSON_CALLBACK'
- }).success(function(data, status) {
- // Now we have a list of the stories (data.list.story)
- // in the data object that the NPR API
- // returns in JSON that looks like:
- // data: { "list": {
- // "title": ...
- // "story": [
- // { "id": ...
- // "title": ...
- }).error(function(data, status) {
- // Some error occurred
- });
- });
現(xiàn)在我們在success函數(shù)的data里有了一個音頻文件的列表。在success回調(diào)函數(shù)里,把這個列表存儲在 $scope 對象,這樣我們就簡單地把它綁定在了 $scope 對象上:
- // from above
- }).success(function(data, status) {
- // Store the list of stories on the scope
- // from the NPR API response object (described above)
- $scope.programs = data.list.story;
- }).error(function(data, status) {
- // Some error occurred
現(xiàn)在,跟剛才一樣, 只需在view里訪問programs,我們就能在view里訪問這個data。你看,使用Angular.js的一個好處就是,當(dāng)承諾模式返回成功結(jié)果時,Angular.js就會自動把這個結(jié)果填進(jìn)你的view里。
- <div ng-controller="PlayerController">
- {{ programs }}
- </div>
試試看:
在下一章里,我們會討論怎么在我們的view里有意義地展示這個data對象,使用一些Angular.js自帶的指令(和更多的一點(diǎn)什么)。
本系列的官方代碼庫可從github上下載:
https://github.com/auser/ng-newsletter-beginner-series.
要將這個代碼庫保存到本地,請先確保安裝了git,clone此代碼庫,然后check out其中的part3分支:
- git clone https://github.com/auser/ng-newsletter-beginner-series.git
- git checkout -b part3
原文鏈接:http://www.ng-newsletter.com/posts/beginner2expert-data-binding.html