2013-05-09 9 views
28

muszę zbudować angularjs klienta dla API wpisywanie JSON tak:Jak obsługiwać dzielenie stron i liczyć przy pomocy zasobów 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" 
    } 
    ] 
} 

Jak mogę dokonać $resource który mapuje do tego? Jeśli użyję isArray=false, otrzymam cały obiekt typu blob jako jeden obiekt, który będzie można wykorzystać do czytania, ale nie mogę na nim zadzwonić pod numer .put(). Jeśli używam isArray, to po prostu nie działa.

Czy jest jakiś czysty sposób to zrobić? A może powinienem wrócić do korzystania z $http?

Odpowiedz

17

Masz kilka opcji. Jeśli możesz zmienić dane wyjściowe serwera, możesz dodać meta-informacje (count, next, previous) jako wartości nagłówków, zamiast dodawać je do treści odpowiedzi.

Twoją drugą opcją jest przekształcenie odpowiedzi za pomocą funkcji transformResponse. Jest dostępny w konfiguracji $ odpowiedzi w kątowym v1.1.2 and later (niestabilnej gałęzi):

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

Jeśli nie chcesz korzystać z niestabilną gałąź możliwe jest również, aby zmienić $ http która wykorzystuje resource $ :

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

Utworzyłem plunker z obu przykładów: http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview

nie jestem pewien, co najlepsze podejście do przekazywania danych meta do końca swojego aplikacyjne n (jeśli tego potrzebujesz). Możesz dodać ją do pierwszego wyniku lub dodać jako oddzielny obiekt - może nie tak elegancko, ale wykona to zadanie.

+0

TransformResponse jest tym, czego potrzebuję, thx. –

+0

@joakimbl, Czy masz pojęcie, jak uzyskać wartości następnej, poprzedniej lub zliczonej? Mam tę samą odpowiedź, o której mowa w pytaniu, a twoje rozwiązania są dokładnie tym, czego potrzebuję, jedynym problemem jest to, że używam "count" do renderowania pagerów, więc muszę jakoś to jakoś uzyskać. – Sergey

+0

Cóż, możesz pobrać je w funkcji transformResponse (np. JSON.parse (data) .count) - ale nie jestem pewien, w jaki sposób przekażesz je dalej. Prawdopodobnie powinieneś po prostu użyć usługi $ http. – joakimbl

15

Wiem, że to pytanie jest trochę stare. Ale myślę, że odpowiedź nie obejmuje głównego problemu - jak uzyskać informacje o paginacji i jak zachować funkcje zasobów dla listy obiektów.

Masz zasadniczo dwa rozwiązania, przekazuj dane paginatora do nagłówków w komunikacie przekształcenia lub użyj $ http, a następnie ręcznie utworzą elementy.

wiadomość 1.Transform

Tu i przedefiniować zapytanie umieścić dane paginacji do nagłówków.

Nagłówki nie są tablicami - to "headersGetter" zwraca nagłówek przez wywołanie nagłówków ("Header-Name") i zwraca wewnętrzny obiekt przez wywołanie nagłówków(). Muszę ustawić małą literę nagłówka.

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

Po tym określam usługę, która obejmuje to i bierze paginację z nagłówków. Nagle nie możemy użyć $ promise.then() i cofnąć wyniku, ponieważ obietnica otrzymuje tylko wynik jako argument, a nie nagłówekGetter, więc musimy użyć zwykłego callback i stworzyć własną obietnicę.

.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 i wystąpienia zasobów

Podczas korzystania $ http zamiast zasobu, nie ma problemu, że nadal chcą korzystać z elementów tablicy jako instancje zasobów i móc wywołać $ save/$ delete, dzięki czemu możliwe jest utworzenie ich ręcznie. Tutaj możesz również użyć zwykłej obietnicy jako zwyczajnej.

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

Wolałbym drugie rozwiązanie, ponieważ jest prostsze.

+0

powinna to być poprawna odpowiedź: –

+0

jak uzyskać dostęp do nagłówka później z pierwszego rozwiązania. – shashwat

+0

Mam trudności z zaimplementowaniem tego, ponieważ używam $ q.all() w wielu moich kontrolerach widoku. Nie mogę wymyślić, jak pobrać z nagłówków takim przykładem. – Kirby

0

Teraz jest jeszcze starszy, ale udało mi się rozwiązać ten problem w jednej fabryce zasobów:

.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

Nie musisz tego robić w ten sposób. Jeśli nie musisz brać pod uwagę informacji o paginacji. Możesz to zrobić, zwracając JSON.parse (dane) .content; Zobacz tutaj: https://bitbucket.org/angular_cz/beerapp-codio/src/f11d63cca45a/src/app/beer/beerFactory.js –

2

I zastanawiał się tego problemu, jak również, i oto co pracował dla mnie. Dodaj transformator odpowiedzi, który pobierze wynik tablicy i ręcznie utworzy obiekt zasobu, który zakładam, że ngResource wykona wewnętrznie tak czy inaczej.

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; 
     } 
    }, 
    }); 
Powiązane problemy