ngResource模塊是angular專門爲RESTful架構而設計的一個模塊,它提供了'$resource'模塊,$resource模塊是基於$http的一個封裝.下面來看看它的詳細用法html
1.引入angular-resource.min.js文件node
2.在模塊中依賴ngResourece,在服務中注入$resourcegit
var HttpREST = angular.module('HttpREST',['ngResource']);
HttpREST.factory('cardResource',function($resource){ return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}}) });
3.$resource的參數:github
$resource(url,{url參數},{自定義方法})express
url: 必填,資源的基礎urljson
url中帶有 ':' 項的是根據第二個參數來進行配置的. 數組
url參數: 選填,配置url中的帶有 ':' 項的參數promise
eg: 架構
('/card/user/:userID/:id',{userID:123,id:'@id'}),那麼userID會被配置爲123.app
另外,在調用$resource()的方法的時候(好比get,query...),能夠傳入參數覆蓋這裏對url參數的配置,這在後面說獲得它的方法的時候再詳解
而id屬性在後面講第三個參數的時候講解
自定義方法:
使用$resource獲取到的資源,或者經過$resource實例化的資源,資源自己會具備一些方法,好比$save,第三個參數用於給資源添加自定義的方法:詳見:http://www.cnblogs.com/liulangmao/p/3907032.html
4.$resource()的方法:
$resource()一共有如下5個方法:
get:
{method:'GET'}
通常用於獲取某個資源:
query:
{method:'GET',isArray:true}
通常用於獲取一整套的資源,以數組形式返回
save:
{method:'POST'}
通常用於保存某個資源,有多是新建的資源,也有多是更新現有的資源
remove:
{method:'DELETE'}
通常用於刪除某個資源
delete:
{method:'DELETE'}
通常用於刪除某個資源
eg:
1.首先經過$resource建立一個服務:
var HttpREST = angular.module('HttpREST',['ngResource']); HttpREST.factory('cardResource',function($resource){ return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}}) });
這個cardResource服務,返回的是一個對象,對象有get,query,save,remove,delete五個方法
2.而後咱們經過cardResource這個服務,來建立另一個獲取資源的服務:
HttpREST.factory('httpCard',function($q,cardResource){ return { getById:function(cardID){ var defer = $q.defer(); cardResource.get({id:cardID},function(data,headers){ defer.resolve(data); },function(data,headers){ defer.reject(data); }); return defer.promise }, query:function(){ var defer = $q.defer(); cardResource.query(function(data,headers){ defer.resolve(data); },function(data,headers){ defer.reject(data); }); return defer.promise } } });
httpCard這個服務返回的對象有兩個方法,一個getById方法,用於經過id加載資源,一個query方法,用於獲取所有的資源.
而後來說解一下get方法和query方法的用法:
get和query方法都是GET類型的請求,他們的調用方式是相同的:
cardResource.action([parameters], [success], [error])
[parameters]: 可選. 一個json對象,用於配置url裏的參數,好比這裏寫了{id:cardID},那麼提交的請求url就是 '/card/user/123/cardID'.
能夠不填,不填就直接按照$resource()裏的url來提交,注意,不填的話,不須要給個空,能夠直接寫success回調,angular可以判斷出它沒有填第一個參數,而不是死板的按照順序來解讀參數.
[success]:可選. 請求成功後的回調函數.回調接受2個參數(注意這裏和$http有所不一樣):
function(data,headers){
//data是請求到的內容
//headers是響應頭
}
[error]:可選. 請求失敗後的回調.回調接受1個參數
function(httpResponse){
//httpResponse暫不知道是什麼. 反正是和響應有關
}
凡是經過$resource返回的對象,必定是json格式的,若是後臺返回的數據不是json,$resource也會按照本身的方式處理成json格式,好比後臺返回字符串'我愛你',那麼若是是get方法,獲得的數據就是:
{
0:我,
1:愛,
2:你
}
而query方法定義了isArray爲true,因此他的返回值必須是數組,而且數組裏的每一個值都必須是json格式的對象.若是返回的是字符串'我愛你',那麼若是是query方法,獲得的數據就是:
[
{0:'我'},
{0:'愛'},
{0:'你'}
]
若是返回的是一個json對象{name:'code_bunny'},那麼獲得的數據就是:
[{name:'code_bunny'}]
因此,在後臺最好就作好相應的處理,按照規範格式返回數據
3. 在控制器中使用httpCard服務來獲取資源:
HttpREST.controller('Card',function($scope,httpCard,cardResource){ //經過id獲取銀行卡 $scope.card_1 = httpCard.getById(1); $scope.card_2 = httpCard.getById(2); $scope.card_3 = httpCard.getById(3); //獲取全部的銀行卡 $scope.cards = httpCard.query(); });
<span>{{card_1['name']}}</span> <span>{{card_1['amount']}}</span> <br/> <span>{{card_2['name']}}</span> <span>{{card_2['amount']}}</span> <br/> <span>{{card_3['name']}}</span> <span>{{card_3['amount']}}</span> <br/>
node:
var cards = [ { id:1, name:'建設銀行', amount:0 }, { id:2, name:'中國銀行', amount:0 }, { id:3, name:'上海銀行', amount:0 } ]; app.get('/card/user/123/:id',function(req,res){ var data = cards[req.params.id-1]; setTimeout(function(){res.send(data)},2000) }); app.get('/card/user/123',function(req,res){ res.send(cards) });
關於card_1...cards明明是promise對象,但視圖中卻正確顯示了資源的問題,請參考:http://www.cnblogs.com/liulangmao/p/3907307.html
4. 在控制器中使用cardResource服務的save方法來更新資源:
HttpREST.controller('Card',function($scope,httpCard,cardResource){ $scope.card_3 = httpCard.getById(3); //更新id爲3的銀行卡 $scope.updataCard = function(){ $scope.card_3.then(function(data){ data.name='工商銀行'; cardResource.save(data); //data.$save() }); }; });
<button ng-click="updataCard()">更新id爲3的銀行卡</button>
<br/>
<span>{{card_3['name']}}</span> <span>{{card_3['amount']}}</span>
node:(這段nodejs同時處理了charge和save)
var url = require('url');
app.post('/card/user/123/:id',function(req,res){ var index = req.params.id-1; var query = url.parse(req.url,true)['query']; if (query.charge){ cards[index]['amount']+= Number(query['amount']) } else { cards[index] = req.body; } res.send(cards[index]); });
點擊後→
cardResource.save(data) 和 data.$save()在這裏,二者是等價的.可是在有參數的時候,他們接受的參數實際上是不一樣的:
使用cardResource.save([parameters], postData, [success], [error])方法時,能夠接受四個參數:
[parameters]: 可選.用於配置url參數,好比配置{userID:124},那麼請求url就會變成 'card/user/124/3',其中的3,仍是從請求體的id屬性獲取的.
一樣,若是沒有參數須要配置,是不要填空的.不存在順序一一對應.能夠直接把postData做爲第一個參數.
postData: 必填. 發送的請求體. save方法是post請求,必需要帶有請求體.
[success]:選填. 響應成功後的回調函數,參數同get方法成功回調裏的參數
[error]:選填. 響應失敗後的回調函數.參數同get方法失敗回調裏的參數
使用data.$save([parameters], [success], [error])方法時,能夠接受三個參數:
[parameters]: 可選.注意它不是用於配置url的參數的.它是用來設置url?後面的參數的! 好比設置{name:'code_bunny'},那麼請求url就會變成'card/user/123/3?name=code_bunny',
經過$save方法來調用save方法,是不可以配置url參數的.它直接就是提交資源本身.
一樣,若是沒有參數須要配置,是不要填空的.不存在順序一一對應.能夠直接把[success]做爲第一個參數.
[success]:選填. 響應成功後的回調函數,參數同get方法成功回調裏的參數
[error]:選填. 響應失敗後的回調函數.參數同get方法失敗回調裏的參數
至於爲何要在then回調裏處理,爲何save後視圖會自動更新,請查看:http://www.cnblogs.com/liulangmao/p/3907307.html 以及 http://www.cnblogs.com/liulangmao/p/3907032.html
5. 在控制器中使用cardResource服務的save方法來新建資源:
(1)新建帶有id的資源:
//添加id爲4的銀行卡 $scope.addCard4 = function(){ var card_4 = new cardResource(); card_4['id'] = 4; card_4['name'] = '浦發銀行'; card_4['amount'] = 0; card_4.$save(function(data){$scope.card_4=data});
//cardResource.save(card_4,function(data){$scope.card_4=data}); };
<span>{{card_4['name']}}</span> <span>{{card_4['amount']}}</span>
node:(這段nodejs同時處理了charge和save)
app.post('/card/user/123/:id',function(req,res){ var index = req.params.id-1; var query = url.parse(req.url,true)['query']; if (query.charge){ cards[index]['amount']+= Number(query['amount']) } else { cards[index] = req.body; } res.send(cards[index]); });
點擊後→
新建資源須要經過new cardResource(), 這樣它就是$resource()的實例,就擁有了$save,$charge等資源的方法:
card_4.$save(function(data){$scope.card_4=data});
cardResource.save(card_4,function(data){$scope.card_4=data});
上面已經說過了,這兩種寫法天然是等價的.但這裏的回調裏須要給$scope_card_4進行賦值,由於原來的$scope下是沒有card_4這個變量的.
(2)新建沒有id的資源:
//添加沒有id的銀行卡 $scope.addCard = function(){ var newCard = new cardResource(); newCard['name'] = '農業銀行'; newCard['amount'] = 0; newCard.$save(function(data){$scope.card_5=data});
cardResource.save(newCard,function(data){$scope.card_5=data});
//newCard.$save(function(data){$scope.card_5=data});
};
<button ng-click="addCard()">添加一張不指定id的銀行卡</button> <br/> <span>{{card_5['name']}}</span> <span>{{card_5['amount']}}</span>
node:
app.post('/card/user/123',function(req,res){ var index = cards.length; cards[index] = req.body; res.send(cards[index]); });
點擊後→
cardResource.save(newCard,function(data){$scope.card_5=data});
newCard.$save(function(data){$scope.card_5=data});
上面已經說過了,這兩種寫法天然是等價的.但這裏的回調裏須要給$scope_card_5進行賦值,由於原來的$scope下是沒有card_5這個變量的.
(1)和(2)的區別在於:
資源是否有id,他們請求的路徑是不一樣的.沒有id的資源會請求'card/user/123',而有id的資源會請求'card/user/123/id',這在node裏的處理是不一樣的.
在$resource中,基本url裏面的 :id 這類經過參數指定的值,若是沒有傳入參數,那麼它提交的路徑裏就不會包含這一項,好比:
return $resource('/card/user/:userID/:id',{userID:123,id:'@id'})
當使用query方法時,是沒有id值的,get請求的路徑就是/card/user/123
可是在node裏面不是這樣的:
app.get('/card/user/123/:id',function(req,res){ //這個只能處理帶有id值的get請求,沒有id請求不能被匹配處處理 }); app.get('/card/user/123',function(req,res){ //這個用來處理沒有id的get請求 }); app.post('/card/user/123/:id',function(req,res){ //這個只能處理帶有id值的post請求,沒有id請求不能被匹配處處理 }); app.post('/card/user/123',function(req,res){ //這個用來處理沒有id的post請求 });
因此,處理有id的資源的post請求和處理沒有id的資源的post請求,在node裏須要寫不一樣的匹配規則,在這裏,對於沒有id的資源,咱們僅做模擬,就把它按照順序保存在數組最後,而後固然仍是把它返回給客戶端.
6. 在控制器中使用cardResource服務的自定義的charge方法來給資源進行充值操做:
//id爲1的建設銀行卡增長100元 $scope.addCharge = function(){ $scope.card_1.then(function(card){ card.$charge({amount:100}); }) }
<button ng-click="addCharge()">給建設銀行的卡充值100元</button> <br/> <span>{{card_1['name']}}</span> <span>{{card_1['amount']}}</span>
node:(這段nodejs同時處理了charge和save)
app.post('/card/user/123/:id',function(req,res){ var index = req.params.id-1; var query = url.parse(req.url,true)['query']; if (query.charge){ cards[index]['amount']+= Number(query['amount']) } else { cards[index] = req.body; } res.send(cards[index]); });
這裏的charge充值方法須要帶有請求參數,?amount=100,因此它不能使用cardResource.charge([params],data,[success],[error])這種方式來請求,只能經過調用資源自身的$charge方法來進行請求.
card.$charge({amount:100})至關於請求了url: 'card/user/123/1?charge=true&amount=100'
即便是RESTful架構,不表示就不能夠在url中帶有參數,帶有參數不影響express對路徑的匹配.獲取路徑參數的方法也就是使用url模塊同樣獲取.
不管POST請求仍是GET請求,均可以帶有參數,也均可以獲取參數.
這裏對'/card/user/123/:id'這個url的請求作了判斷,獲取它的參數,而後判斷參數裏的charge是否等於true,是的話表示充值操做.不是的話表示更新資源操做.分別對資源進行處理,最後都是把操做過的資源返回給客戶端.
其中,url.parse(req.url,true),若是不帶有true,不會把參數解析成json格式.
點擊後→
7. 在控制器中使用cardResource服務的delete方法來刪除資源:
//刪除id爲1的銀行卡 $scope.delCard1 = function(){ $scope.card_1.then(function(card){ card.$delete(); }) }
<button ng-click="delCard1()">將id爲1的銀行卡刪掉</button> <br/> <span>{{card_1['name']}}</span> <span>{{card_1['amount']}}</span>
node:
app.delete('/card/user/123/:id',function(req,res){ var index = req.params.id-1; cards[index] = null; res.send({}) });
點擊後→
這裏有兩點須要注意:
1.card.$delete()不等同於cardResource.delete(card),由於它這裏是'DELETE'方式的請求,不是POST方式的請求,當咱們使用card.$delete()的時候,它是把card做爲請求體發送給後臺的(至關於POST請求體).可是當咱們使用cardResource.delete(card)的時候,它是把card對象解析成url參數一塊兒傳給後臺的(至關於GET請求裏url後面的參數).也就是說,card.$delete()請求的url是'card/user/123/1',附帶請求體爲card. 而cardResource.delete(card)請求的url是'card/user/123/1?amount=0&name=建設銀行'.
還有很重要的一點,其實請求url是'card/user/123/1?amount=0&name=建設銀行'在這個例子中並不會改變後臺的處理和返回,可是對於angular來講,card.$delete()會使用返回值去填充card,更新視圖,可是cardResource.delete(card),它並不是請求體就是card,因此返回值不會去填充card,不會更新視圖.因此,在使用delete方法時,應該直接使用$delete,而不是delete.(remove亦然)
2.刪除之後,cards[0]就變成空的null,可是不能返回null,由於$resource必須返回json格式,因此要返回{}
完整代碼地址:https://github.com/OOP-Code-Bunny/angular/tree/master/OREILLY/18.6%20%24http(ngResource)