2013-05-09 9 views
28

Ich habe einen AngularJS Client für eine API JSON wie dies die Ausgabe zu erstellen:Wie behandelt man Seitenzahlen und zählt mit angularjs resources?

{ 
    "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" 
    } 
    ] 
} 

Wie kann ich eine $resource machen, die diese Karten? Wenn ich isArray=false verwende, erhalte ich den gesamten Blob als ein Objekt, das zum Lesen verwendet werden kann, aber ich kann .put() nicht darauf aufrufen. Wenn ich isArray benutze, funktioniert es einfach nicht.

Gibt es einen sauberen Weg, dies zu tun? Oder sollte ich wieder $http verwenden?

Antwort

17

Sie haben ein paar Optionen. Wenn Sie die Server-Ausgabe ändern können, können Sie die Meta-Informationen (Anzahl, nächste, vorherige) als Header-Werte hinzufügen, anstatt sie im Antworttextkörper hinzuzufügen.

Ihre zweite Option besteht darin, die Antwort mit transformResponse zu transformieren. Dies ist als $ response Konfiguration in Winkel v1.1.2 and later (der Unstable-Zweig):

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

Wenn Sie nicht wollen, den Unstable-Zweig zu verwenden ist es auch möglich, den $ http die $ Ressource Anwendungen zu ändern :

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

ich habe eine Plunker mit beiden Beispielen erstellt: http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview

ich bin nicht sicher, was der beste Ansatz für die Meta-Daten auf den Rest Ihres applicatio für das Bestehen n (wenn Sie es brauchen). Sie könnten es an das erste Ergebnis anhängen oder es als separates Objekt hinzufügen - vielleicht nicht so elegant, aber es wird die Aufgabe erledigen.

+0

TransformResponse ist was ich brauche, thx. –

+0

@joakimbl, Haben Sie eine Idee, wie Sie nächste, vorherige oder Zählwerte erhalten? Ich habe die gleiche Antwort wie in Frage erwähnt, und Ihre Lösungen sind genau das, was ich brauche, das einzige Problem ist, dass ich 'Count' zum Rendern Pager verwenden, so muss ich irgendwie Wert erhalten. – Sergey

+0

Nun, Sie können sie in der Funktion transformResponse erhalten (z. B. JSON.parse (Daten) .count) - aber ich bin mir nicht sicher, wie Sie sie weiterleiten würden. Sie sollten wahrscheinlich nur den $ http-Dienst verwenden. – joakimbl

15

Ich weiß, diese Frage ist ein bisschen alt. Aber ich denke, die Antwort behandelt nicht das Hauptproblem - wie man Paginierungsinformationen erhält und wie man Resource-Features für eine Liste von Objekten behält.

Sie haben im Grunde zwei Lösungen, paginator Daten in Header in Transformations Nachricht übergeben oder http $ und dann Elemente manuell instanziieren.

1.Transform Nachricht

i Abfrage neu zu definieren Hier Paginierung Daten in Header zu setzen.

Headers kein Array - it "headersGetter" ist, die zurück Header von Headern Aufruf ('Header Name') und kehrt innere Objekt durch Headern() aufrufen. Ich muss Header Kleinbuchstaben setzen.

Danach definiere ich Service, die dies einkapseln und Seitenumbruch aus Headern nehmen. Sudenly können wir $ promise.then() nicht verwenden und Ergebnis zurücksenden, weil das Versprechen nur das Ergebnis als Argument und nicht den HeaderGetter erhält, also müssen wir den gewöhnlichen Callback verwenden und eigene Versprechen erstellen.

.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.Using $ http und instanziiert Ressourcen

Wenn $ http statt Ressource verwendet wird, ist es ein Problem, dass Sie immer noch Elemente von Array verwenden möchten als Ressourceninstanzen und in der Lage sein $ anrufen Speichern/$ löschen, so dass es möglich ist, sie manuell zu instanziieren. Hier können Sie auch gewöhnliche Versprechen als ussual verwenden.

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

würde ich zweite Lösung bevorzugen, weil seine einfacher.

+0

Dies sollte die richtige Antwort sein –

+0

Wie würden Sie später von Ihrer ersten Lösung Header zugreifen. – shashwat

+0

Ich habe Schwierigkeiten damit, dies zu implementieren, weil ich $ q.all() in vielen meiner View-Controller verwende. Ich kann nicht herausfinden, wie man mit einem solchen Beispiel aus den Headern greift. – Kirby

0

Inzwischen ist dies sogar noch älter, aber ich schaffte es dies in einer einzigen Ressource Fabrik zu lösen:

.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

Sie müssen es nicht so machen. Wenn Sie Paginierungsinformationen nicht berücksichtigen müssen. Sie können dies tun, indem Sie einfach JSON.parse (data) .content; Schauen Sie hier: https://bitbucket.org/angular_cz/beerapp-codio/src/f11d63cca45a/src/app/beer/beerFactory.js –

2

ich in dieses Problem auch ratlos, und hier ist was für mich gearbeitet. Fügen Sie einen Antwort-Transformer hinzu, der das Array-Ergebnis übernehmen und manuell ein Ressourcenobjekt erstellen würde. Ich nehme an, ngResource würde das trotzdem intern tun.

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; 
     } 
    }, 
    }); 
Verwandte Themen