2013-05-09 15 views
28

我必須建立一個angularjs客戶端的API輸出JSON是這樣的:如何處理分頁和計數與angularjs資源?

{ 
    "count": 10, 
    "next": null, 
    "previous": "http://site.tld/api/items/?start=4" 
    "results": [ 
    { 
     "url": "http://site.tld/api/items/1.json", 
     "title": "test", 
     "description": "", 
     "user": "http://site.tld/api/users/4.json", 
     "creation_datetime": "2013-05-08T14:31:43.428" 
    }, 
    { 
     "url": "http://site.tld/api/items/2.json", 
     "title": "test2", 
     "description": "", 
     "user": "http://site.tld/api/users/1.json", 
     "creation_datetime": "2013-05-08T14:31:43.428" 
    }, 
    { 
     "url": "http://site.tld/api/items/3.json", 
     "title": "test3", 
     "description": "", 
     "user": "http://site.tld/api/users/2.json", 
     "creation_datetime": "2013-05-08T14:31:43.428" 
    } 
    ] 
} 

我怎樣才能使一個$resource映射到這一點?如果我使用isArray=false,我會將整個blob作爲一個對象,可用於閱讀,但我無法撥打.put()。如果我使用isArray,它只是不起作用。

有沒有乾淨的方法來做到這一點?或者我應該回去使用$http

回答

17

你有幾個選項。如果您可以更改服務器輸出,則可以將元信息(count,next,previous)添加爲標題值,而不是將它們添加到響應正文中。

你的第二個選擇是用transformResponse轉換響應。這可作爲角v1.1.2 and later(不穩定分支)一個響應$配置:

var Data = $resource('./data.json',{},{ 
    list:{isArray:true,method:'get', 
    transformResponse: function (data, headers) { 
     return JSON.parse(data).results; 
    }} 
}); 

如果你不希望使用不穩定的分支,也可以改變$ HTTP這$資源用途:

$http.defaults.transformResponse.push(function(data){ 
    if(data && data.results){ 
    return data.results; 
    } 
}); 

我已經創建了兩個例子plunker:http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview

我不知道什麼傳遞的元數據到你的應用A的其餘部分的最佳方法ñ(如果你需要它)。你可以將它附加到第一個結果,或者將它作爲一個單獨的對象添加 - 可能不那麼優雅,但它會完成工作。

+0

TransformResponse是我需要的,thx。 – 2013-05-09 17:43:41

+0

@joakimbl,你有什麼想法如何獲得下一個,以前或計數值?我的問題和上面提到的一樣,你的解決方案正是我需要的,唯一的問題是我使用'count'來呈現分頁器,所以我需要以某種方式獲得它的值。 – Sergey 2013-11-28 15:55:22

+0

那麼,你可以在transformResponse函數中獲取它們(例如JSON.parse(data).count) - 但我不確定你會如何通過它們。您應該使用$ http服務。 – joakimbl 2013-11-30 10:33:54

15

我知道這個問題有點老了。但我認爲答案不包括主要問題 - 如何獲取分頁信息以及如何爲對象列表保留資源特徵。

您基本上有兩種解決方案,將paginator數據傳遞到變換消息中的標題或使用$ http,然後手動實例化項目。

1.Transform消息

在這裏,我重新定義查詢把分頁數據分成報頭。

標題不是數組 - 它是「headersGetter」,它通過調用標頭('Header-Name')返回標頭,並通過調用標頭()返回內部對象。我必須設置標題小寫。

var PAGINATION_TOTAL = 'pagination-total-elements'; 
var PAGINATION_SIZE = 'pagination-size'; 

... 

.factory('BeerResourceFactory', function($resource, API_URI) { 
     return $resource(API_URI + '/beer/:id', 
      {'id': '@id'}, 
      { 
       'update': {method: 'PUT'}, 
       'query' : {method: 'GET', isArray:true, transformResponse : function(data, headers) { 
       var jsonData = JSON.parse(data); 
       headers()[PAGINATION_TOTAL] = jsonData.totalElements; 
       headers()[PAGINATION_SIZE] = jsonData.size; 

       return jsonData.content; 
       }} 
      }); 
     }) 

之後,我定義服務,這種封裝和頭採取分頁。我們暫時不能使用$ promise.then()並導致結果,因爲promise的結果只是作爲參數而不是headersGetter,所以我們必須使用普通的回調函數並創建自己的promise。

.service('beerService', function(BeerResourceFactory, $q) { 
    this.query = function(filter) { 

      var defer = $q.defer(); 

      BeerResourceFactory.query(filter, function(result, headers) { 
      var promiseResult = { 
       beers: result, 
       paging: { 
       totalItems: headers(PAGINATION_TOTAL), 
       perPage: headers(PAGINATION_SIZE) 
       } 
      }; 

      defer.resolve(promiseResult); 
      }); 

      return defer.promise; 
    } 

2.使用$ http和實例化資源

當使用$,而不是資源的HTTP,還有就是你仍然想使用數組的元素作爲資源實例和能夠調用$問題保存/ $刪除,因此可以手動實例化它們。在這裏,你也可以使用普通的承諾。

.service('beerService', function($http, BeerResourceFactory, API_URI) { 
    this.query = function(filter) { 
     return $http.get(API_URI + '/beer', {params: filter}) 
       .then(function(response) { 

       var transformedList = response.data.content.map(function(element) { 
        return new BeerResourceFactory(element); 
       }); 

       return { 
        beers: transformedList, 
        paging: { 
        totalItems: response.data.totalElements, 
        perPage: response.data.size 
        } 
       }; 
       }); 
     }; 

我寧願第二個解決方案,因爲它更簡單。

+0

這應該是正確答案 – 2016-03-12 00:10:14

+0

您將如何從第一個解決方案中稍後訪問標頭。 – shashwat 2017-01-10 10:05:27

+0

我很難實現這一點,因爲我在很多視圖控制器中使用$ q.all()。我無法弄清楚如何從頭文件中獲取這樣的例子。 – Kirby 2017-01-30 21:22:21

0

現在這是更老,但我設法在一個單一的資源工廠來解決這個問題:

.factory('BeerResourceFactory', function($resource, API_URI) { 
    var resource = $resource(API_URI + '/beer/:id', 
     {'id': '@id'}, 
     { 
      'update': {method: 'PUT'}, 
      'query' : {method: 'GET', isArray:true, transformResponse : function(data) { 
      var jsonData = angular.fromJson(data); 
      jsonData.beers = jsonData.beers.map(function (beer) { 
       return new resource(beer) 
      }); 

      return jsonData.content; 
      }} 
     }); 
     return resource; 
    }) 
+0

你不需要這樣做。 如果你不需要考慮分頁信息。你可以通過返回JSON.parse(data).content來完成; 看這裏:https://bitbucket.org/angular_cz/beerapp-codio/src/f11d63cca45a/src/app/beer/beerFactory.js – 2015-08-07 22:31:32

2

我難倒了這個問題爲好,這裏是爲我工作。添加一個響應變換器,它將獲取數組結果並手動創建一個資源對象,我假設ngResource會在內部完成。

var Plan = $resource(apiPath + 'plans/:planId/', {planId:'@id'}, { 
    query: { 
     isArray: false, 
     transformResponse: function(response){ 
     response = angular.fromJson(response); 
     response.results = response.results.map(function(plan) { 
      return new Plan(plan); 
     }); 
     return response; 
     } 
    }, 
    });