如何使用angularjs资源处理分页和计数?

时间:2013-05-09 15:44:47

标签: rest angularjs angular-resource

我必须为输出JSON的API构建一个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

4 个答案:

答案 0 :(得分: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; 
   }}
});

如果您不想使用unstable分支,也可以更改$ resource使用的$ http:

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

我用两个例子创建了一个plunker:http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview

我不确定将元数据传递给应用程序其余部分的最佳方法(如果需要)。您可以将其附加到第一个结果,或将其添加为单独的对象 - 可能不是那么优雅,但它可以完成工作。

答案 1 :(得分:16)

我知道这个问题有点老了。但我认为答案并不涵盖主要问题 - 如何获取分页信息以及如何保留资源功能以用于对象列表。

您基本上有两个解决方案,将分页器数据传递到转换消息中的标头或使用$ http然后手动实例化项目。

1.转换消息

这里我重新定义查询以将分页数据放入标题中。

标题不是一个数组 - 它是" headersGetter"它通过调用标题返回标题(' Header-Name')并通过调用headers()返回内部对象。我必须将标题设置为小写。

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而不是资源时,您仍然希望使用数组元素作为资源实例并且能够调用$ save / $ delete,因此可以手动实例化它们。在这里你也可以使用普通的承诺作为ussual。

.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
                  }
                };
              });
         };

我更喜欢第二种解决方案,因为它更简单。

答案 2 :(得分: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;
      }
    },
  });

答案 3 :(得分: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;
  })