在之前的文章中講到了在使用$resource的時候,有一個isArray屬性. 這個屬性在兩個地方有提到:
1. angular學習筆記(二十八)-$http(6)-使用ngResource模組構建RESTful架構
$resource的四個方法: query方法,get方法,save方法,remove方法,delete方法
這四個方法裡,唯獨query方法,它的isArray屬性是true,所以,query接受到的資料是陣列,而其餘四個方法,接收到的資料必須不能是陣列
2. angular學習筆記(二十八-附1)-$resource中的資源的方法
$resource的自定義方法: 比如該篇的栗子中使用的$charge方法,在定義自定義方法的時候,也要指定isArray屬性.不指定的話預設是false.
如果我們不設定isArray為true,但是後臺卻給它返回一個陣列資源,是會報錯的.
那麼,如果在使用get方法,save方法,remove方法,delete方法的時候,需要返回陣列物件呢? 答案是不能的.因為$resource這個服務沒有提供相應的配置方法.
那麼,如果自定義一個方法,設定isArray為true,是不是就可以接受陣列格式的返回值了呢? 答案是,要看情況!
比如下面這段程式碼:
var notePad = angular.module('notePad',['ngResource']); notePad.factory('myNotes',['$resource',function($resource){ return $resource('/notes/:id',{id:'@id'},{mysave:{method:'POST',isArray:true}}) }]); notePad.factory('loadNotes',['myNotes','$q',function(myNotes,$q){ return function(){ var defer = $q.defer(); myNotes.query(function(notes){ defer.resolve(notes); },function(err){ defer.reject(err) }); return defer.promise } }]); notePad.factory('loadNote',['myNotes','$q',function(myNotes,$q){ return function(noteId){ var defer = $q.defer(); myNotes.get({id:noteId},function(note){ defer.resolve(note); },function(err){ defer.reject(err) }); return defer.promise } }]); notePad.directive('notepad',['loadNotes','myNotes',function(loadNotes,myNotes){ return { restrict:'EA', templateUrl:'template.html', scope:{}, link:function(scope,iEle,iAttr){ scope.editMode = false; scope.curText = ''; scope.ifNew = true; loadNotes().then(function(data){scope.notes=data},function(data){}); var editBox = iEle.find('.edit'); editBox.bind('keydown keyup',function(){ scope.curText = $(this).html() }); scope.editNote = function(id){ scope.editMode = true; if(id != undefined){ scope.curText = scope.notes[id]['content'] } else { scope.curText = ''; } }; scope.saveNote = function(){ scope.editMode = false; if(scope.ifNew){ var newNote = new myNotes(); newNote.content = scope.curText; newNote.title = scope.curText.length>5 ? scope.curText.substring(0,5)+'...' : scope.curText; newNote.id = scope.notes.length; newNote.$mysave(function(data){console.log(data)}) } } } } }]);
內容比較多,只看關鍵部分程式碼:
1.myNotes服務通過$resource建立$resource()物件,然後給它新增自定義的mysave方法,設定isArray屬性為false.
2.例項化一個newNote資源,然後呼叫自定義的$mysave方法
後臺我們給它返回一個陣列物件:
var notes = [{ 'title':'吃飯', 'content':'吃飯啊', 'id':0 },{ 'title':'睡覺', 'content':'睡覺啊', 'id':1 },{ 'title':'喂兔子', 'content':'喂兔子啊', 'id':2 }]; app.post('/notes/:id',function(req,res){ var noteId = req.params.id; notes[noteId] = req.body; res.send(notes) });
結果報錯:
這個很好理解,因為我們設定了isArray是false嘛.
然後我把isArray屬性改為true:
結果還是報錯:
百思不得其解後去看了angular-resource的原始碼,發現裡面有這樣一段:
var isInstanceCall = this instanceof Resource; var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data)); if (action.isArray) { value.length = 0; forEach(data, function (item) { if (typeof item === "object") { value.push(new Resource(item)); } else { // Valid JSON values may be string literals, and these should not be converted // into objects. These items will not have access to the Resource prototype // methods, but unfortunately there value.push(item); } }); }
注意這裡的value物件,並非設定isArray為true時,它就是[],首先要求isInstanceCall是false,然後再判斷isArray...
所以,這裡的newNote是$resource()的例項,這樣,isArray無論如何配置,它都不能接受陣列格式的返回資料.並且必須配置為false.
所以這裡應該這樣做:
newNote.$mysave(function(data){console.log(data)})
//改為:
myNotes.mysave(newNote,function(data){console.log(data)});
不要使用資源例項的方法,而是直接使用$resource()的方法.這樣就可以正確接收陣列格式的返回值了.
angular這樣設計,應該是符合RESTful架構風的(我猜的),因為提交一個資源,那麼返回的也應該是一個資源,而不應該是整個陣列,所以應該儘量避免這種做法.這裡只是我自己做練習的時候遇到這樣的情況.
完整程式碼參考: angular指令實戰-notepad