web-dev-qa-db-ja.com

angularjsリソースでページネーションを処理して数える方法は?

次のように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全体が1つのオブジェクトとして取得され、読み取りに使用できますが、.put()を呼び出すことはできません。 isArrayを使用すると、機能しません。

これを行うクリーンな方法はありますか?または、_$http_の使用に戻る必要がありますか?

28
e-satis

いくつかのオプションがあります。サーバーの出力を変更できる場合は、応答の本文に追加する代わりに、ヘッダー情報としてメタ情報(count、next、previous)を追加できます。

2番目のオプションは、transformResponseを使用して応答を変換することです。これは、angular v1.1.2以降 (unstableブランチ)の$ 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;
  }
});

私は両方の例でプランカーを作成しました: http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview

メタデータをアプリケーションの残りの部分に渡すための最善の方法(必要な場合)がわかりません。最初の結果に追加するか、別のオブジェクトとして追加することができます-それほどエレガントではないかもしれませんが、それで仕事が完了します。

17
joakimbl

この質問は少し古いです。しかし、私は答えは主な問題をカバーしないと思います-ページネーション情報を取得する方法とオブジェクトのリストのリソース機能を維持する方法。

基本的に2つの解決策があります。ページネーションデータを変換メッセージのヘッダーに渡すか、$ httpを使用して、アイテムを手動でインスタンス化します。

1。変換メッセージ

ここで、ページ付けデータをヘッダーに入れるクエリを再定義します。

Headersは配列ではありません-"headersGetter"で、headers( '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はheadersGetterではなく結果としてのみ結果を取得するため、$ promise.then()と結果を再利用することはできないため、通常のコールバックを使用して独自の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を呼び出せるようにする必要があるため、それらを手動でインスタンス化することができます。ここでは、通常の約束を通常どおり使用することもできます。

.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;
      }
    },
  });
2
Gaurav Butola

今ではこれはさらに古くなっていますが、単一のリソースファクトリでこれを解決することができました。

.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
Dave