2013-05-09 9 views
28

devo costruire un client angularjs per un'API JSON output come questo:Come gestire l'impaginazione e contare con le risorse 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" 
    } 
    ] 
} 

Come posso fare una $resource che mappa a questo? Se utilizzo isArray=false, otterrò l'intero blob come un oggetto, utilizzabile per la lettura, ma non posso chiamare .put() su di esso. Se uso isArray, semplicemente non funziona.

C'è qualche modo pulito per farlo? O dovrei tornare a utilizzare $http?

risposta

17

Hai un paio di opzioni. Se è possibile modificare l'output del server, è possibile aggiungere le meta informazioni (count, next, previous) come valori di intestazione invece di aggiungerli nel corpo della risposta.

La seconda opzione è trasformare la risposta con transformResponse. Questo è disponibile come configurazione $ risposta a angolare v1.1.2 and later (il ramo instabile):

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

Se non si desidera utilizzare il ramo unstable è anche possibile cambiare il $ http che utilizza risorse $ :

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

ho creato un plunker con entrambi gli esempi: http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview

non sono sicuro di ciò che l'approccio migliore per trasmettere i meta-dati per il resto della tua applicatio n (se ne hai bisogno). È possibile aggiungerlo al primo risultato o aggiungerlo come oggetto separato, forse non così elegante, ma il lavoro verrà completato.

+0

TransformResponse è ciò di cui ho bisogno, grazie. –

+0

@joakimbl, Hai qualche idea su come ottenere i valori successivo, precedente o di conteggio? Ho la stessa risposta di cui ho parlato e le tue soluzioni sono esattamente ciò di cui ho bisogno, l'unico problema è che uso "count" per renderizzare il pager, quindi ho bisogno di ottenerlo in qualche modo. – Sergey

+0

Bene, puoi ottenerli nella funzione transformResponse (ad es. JSON.parse (dati) .count) - ma non sono sicuro di come li avresti passati oltre. Probabilmente dovresti semplicemente usare il servizio $ http. – joakimbl

15

So che questa domanda è un po 'vecchia. Ma penso che la risposta non copra il problema principale: come ottenere le informazioni sulla paginazione e come mantenere le funzionalità delle risorse per l'elenco degli oggetti.

Avete fondamentalmente due soluzioni, passate i dati di paginator in intestazioni nel messaggio di trasformazione o utilizzate $ http e quindi istanziate manualmente gli elementi.

messaggio 1.Transform

Here i ridefinire query per inserire i dati di impaginazione nelle intestazioni.

Le intestazioni non sono un array: è "headersGetter" che restituisce l'intestazione chiamando le intestazioni ('Header-Name') e restituisce l'oggetto interno chiamando le intestazioni(). Devo impostare l'intestazione in minuscolo.

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

Dopo che io definisco servizio che incapsula questo e prendere impaginazione dalle intestazioni. All'improvviso non possiamo usare $ promise.then() e tornare indietro perché la promessa ottiene solo risultato come argomento e non come headersGetter, quindi dobbiamo usare il callback ordinario e creare la propria promessa.

.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.Tramite $ http e creare un'istanza della risorsa

Quando si usa $ http invece di risorse, non v'è problema che si vuole ancora utilizzare gli elementi della matrice come istanze di risorse e di essere in grado di chiamare $ salva/$ elimina, quindi è possibile istanziarli manualmente. Qui puoi anche usare la normale promessa come usuale.

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

Preferirei seconda soluzione, perché è più semplice.

+0

questa dovrebbe essere la risposta corretta –

+0

come potreste accedere all'intestazione più tardi dalla prima soluzione. – shashwat

+0

Ho difficoltà a implementarlo perché uso $ q.all() in molti miei controller di visualizzazione. Non riesco a capire come afferrare le intestazioni con un esempio del genere. – Kirby

0

Ormai questo è ancora più vecchio, ma sono riuscito a risolvere questo in una sola fabbrica risorsa:

.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

Non hai bisogno di farlo in quel modo. Se non è necessario tenere conto delle informazioni di impaginazione. Puoi farlo semplicemente restituendo JSON.parse (data) .content; Guarda qui: https://bitbucket.org/angular_cz/beerapp-codio/src/f11d63cca45a/src/app/beer/beerFactory.js –

2

ho perplesso in questo problema così, ed ecco cosa ha funzionato per me. Aggiungi un trasformatore di risposta che prenda il risultato dell'array e crei manualmente un oggetto risorsa, suppongo che ngResource faccia comunque internamente.

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; 
     } 
    }, 
    }); 
Problemi correlati