【问题标题】:How to handle pagination and count with angularjs resources?如何使用 angularjs 资源处理分页和计数?
【发布时间】:2016-04-18 18:20:51
【问题描述】:

我必须为输出 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

【问题讨论】:

    标签: rest angularjs angular-resource


    【解决方案1】:

    您有几个选择。如果您可以更改服务器输出,则可以将元信息(计数、下一个、上一个)添加为标头值,而不是将它们添加到响应正文中。

    您的第二个选项是使用 transformResponse 转换响应。这可作为 angular v1.1.2 and later(不稳定分支)中的 $response 配置使用:

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

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

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

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

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

    【讨论】:

    • @joakimbl,您知道如何获取下一个、上一个或计数值吗?我有与问题相同的响应,您的解决方案正是我所需要的,唯一的问题是我使用“计数”来呈现寻呼机,所以我需要以某种方式获得它的价值。
    • 好吧,您可以在 transformResponse 函数中获取它们(例如 JSON.parse(data).count) - 但我不确定您将如何进一步传递它们。您可能应该只使用 $http 服务。
    • 我认为这个答案不能同时解决这两个问题。第一个:“如何传递分页信息”和第二个:“在收集的对象上保留资源特征”。所以我写了自己的答案。
    【解决方案2】:

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

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

    1.转换消息

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

    Headers 不是一个数组——它是“headersGetter”,它通过调用 headers('Header-Name') 返回 header,并通过调用 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实例化Resource

    当使用$http 代替resource 时,问题是你仍然想使用数组的元素作为资源实例并且能够调用$save / $delete,所以可以手动实例化它们。在这里你也可以像往常一样使用普通的promise。

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

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

    【讨论】:

    • 您以后如何从您的第一个解决方案访问标头。
    • 我很难实现这一点,因为我在很多视图控制器中都使用了 $q.all()。我不知道如何用这样的例子从标题中抓取。
    【解决方案3】:

    我也遇到了这个问题,这对我有用。添加一个响应转换器,它将获取数组结果并手动创建一个资源对象,我假设 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;
          }
        },
      });
    

    【讨论】:

      【解决方案4】:

      到现在为止,这甚至更老了,但我设法在一个资源工厂中解决了这个问题:

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

      【讨论】:

      猜你喜欢
      • 2013-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      • 2011-05-05
      相关资源
      最近更新 更多