通過$resource獲取到的資源,或者是通過$resource例項化的資源,資源本身就擁有了一些方法,$save,$delete,$remove,可以直接呼叫來儲存該資源:
比如有一個$resource建立的服務:
var service = angular.module('myRecipe.service',['ngResource']); service.factory('Recipe',['$resource',function($resource){ return $resource('/recipe/:id',{id:'@id'}); }]); service.factory('loadRecipes',['Recipe','$q',function(Recipe,$q){ return function(){ var defer = $q.defer(); Recipe.query(function(recipes){ defer.resolve(recipes) },function(err){ defer.reject(err) }); return defer.promise } }]); service.factory('loadRecipe',['Recipe','$q','$route','$routeParams',function(Recipe,$q,$route,$routeParams){ return function(){ var defer = $q.defer(); Recipe.get({id:$route.current.params.recipeId},function(recipe){ defer.resolve(recipe) },function(err){ defer.reject(err) }); return defer.promise } }]);
然後我通過loadRecipe方法獲取到了一個recipe,修改了recipe後需要對它進行提交儲存,以下兩種方式是一樣的:
1. 通過$resource的save方法(第一個引數是請求提,第二個引數是請求完成後的回撥)
Recipe.save($scope.recipe,function(){ $location.path('/view/'+$scope.recipe.id) });
2. 由於recipe本身就是通過$resource獲取的資源,所以它擁有$save方法,$save方法裡的函式就是儲存成功後的回撥.
$scope.recipe.$save(function(){ $location.path('/view/'+$scope.recipe.id) });
除了通過loadRecipe獲取到的資源,通過$resource例項化的資源也有$save方法:
比如下面的recipe:
$scope.recipe = new Recipe({ ingredients:[{}] }); $scope.save = function(invalid){ if(invalid){ return false } Recipe.save($scope.recipe,function(recipe){ $location.path('/view/'+recipe.id) }); };
$resource()中第二個引數{id:'@id'},表示url中的:id 將會使用資源的id屬性值,也就是recipe的id屬性值.
還可以通過$resource()第三個引數來給資源自定義方法:
return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}})
來分析一下這裡的第三個引數 {charge:{method:'POST',params:{charge:true},isArray:false}}
1.charge是自定義方法的名字,資源就可以通過$charge()來呼叫該自定義方法
2.charge屬性值是一個json物件,裡面有三個屬性:
method: 該方法的請求方式: 'POST','GET','DELETE','PUT',等,這裡的請求方式可以自定義方法,$resource()返回的物件的get,query,save,remove,delete裡用到的只有'GET','POST','DELETE'三種請求方式,但是這裡自定義的方法,可以使用$http的所以請求方式. 所以,如果要自定義請求方式,也是通過自定義方法來建立的.
params: 定義請求url後面的引數,這裡是{charge:true},就會向url?charge=true傳送請求
isArray: 定義返回的資料的格式是否是陣列
3.charge屬性值除了2裡說到的三個屬性,還有所有$http裡所有可配置的項:
headers:,
transformRequest:,
transformResponse:,
cache:,
timeout:,
withCredentials:
這些項的意思和具體怎麼配置,請參考之前將$http的文章,他們是一致的.
eg:
HttpREST.factory('cardResource',function($resource){ return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}}) }); 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 } } }); $scope.addCharge = function(){ $scope.card_1.then(function(card){ card.$charge({amount:100}); }) }
注意,card_1得到的是promise物件,而不是資源本身,要獲得實際的資源,要通過它的then方法裡的函式的引數來獲得.關於這個問題,請檢視:
http://www.cnblogs.com/liulangmao/p/3907307.html
$charge裡的參數列示url後面的引數,也就是說:
card.$charge({amount:100}) 向/card/user/123/1?charge=turn&amount=100傳送了post請求,請求體就是card
請求url裡的1是因為在$resource()第二個引數中配置了{id:@id},所以就是card的id,
請求引數是charge=true是因為在$resource()第三個引數中配置了{charge:{params:{charge:true}}
請求方式是post是因為在$resource()第三個引數中配置了{charge:{method:'POST',params:{charge:true}}}
請求引數是amount=100是因為在呼叫card.$charge()的時候傳入了引數{amount:100}
資源的方法還有一個特性: 在請求完成後,會自動用返回值來填充呼叫方法的資源,繼而更新檢視.無需在回撥手動處理:
eg:
html:
<button ng-click="addCharge()">給建設銀行的卡充值100元</button> <br/> <span>{{card_1['name']}}</span> <span>{{card_1['amount']}}</span> <br/>
js:
$scope.addCharge = function(){ $scope.card_1.then(function(card){ card.$charge({amount:100}); }) }
node:
app.post('/card/user/123/:id',function(req,res){ var index = req.params.id ? req.params.id-1 : cards.length; 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]); });
點選充值後,後臺會給建設銀行卡新增100元,然後再把建設銀行卡這個資源返回給客戶端:
點選按鈕後:
我們可以看到,在card.$charge({amount:100})這個呼叫中,我們並沒有書寫回撥來改變$scope.card_1,但是檢視裡card_1['amount']確實發生了變化,原因是,
angular自動將返回值填充了card,而card是card_1的$$v屬性值(關於$$v請檢視http://www.cnblogs.com/liulangmao/p/3907307.html),所以檢視裡的card_1也會被更新.