Как обрабатывать нумерацию страниц с помощью angularjs?
Я должен построить клиент angularjs для API, выводящий JSON, вот так:
{
"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
?
4 ответа
У вас есть несколько вариантов. Если вы можете изменить выходные данные сервера, вы можете добавить метаинформацию (count, next, previous) в качестве значений заголовка вместо того, чтобы добавлять их в тело ответа.
Второй вариант - преобразовать ответ с помощью transformResponse. Это доступно как конфигурация $ response в angular v1.1.2 и позже (нестабильная ветвь):
var Data = $resource('./data.json',{},{
list:{isArray:true,method:'get',
transformResponse: function (data, headers) {
return JSON.parse(data).results;
}}
});
Если вы не хотите использовать нестабильную ветку, также можно изменить $http, который использует $resource:
$http.defaults.transformResponse.push(function(data){
if(data && data.results){
return data.results;
}
});
Я создал плункер с обоими примерами: http://plnkr.co/edit/PmYotP0eo5k41Z6ZCxl4?p=preview
Я не уверен, что лучше всего подходит для передачи метаданных остальной части вашего приложения (если вам это нужно). Вы можете добавить его к первому результату или добавить его в качестве отдельного объекта - возможно, не так элегантно, но это сделает работу.
Я знаю, что этот вопрос немного староват. Но я думаю, что ответ не охватывает основную проблему - как получить информацию о разбиении на страницы и как сохранить функции ресурса для списка объектов.
У вас есть два основных решения: передать данные в формате paginator в заголовки в сообщении преобразования или использовать $ http, а затем создать элементы вручную.
1. преобразовать сообщение
Здесь я переопределяю запрос, чтобы поместить данные разбивки на страницы в заголовки.
Заголовки - это не массив - это "headersGetter", который возвращает заголовок, вызывая заголовки ("Header-Name"), и возвращает внутренний объект, вызывая заголовки (). Я должен установить нижний регистр заголовка.
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;
}}
});
})
После этого я определяю сервис, который инкапсулирует это и берет нумерацию страниц из заголовков. Внезапно мы не можем использовать $ обещание.then() и возвращать результат, потому что обещание получает только результат в качестве аргумента, а не заголовки, поэтому мы должны использовать обычный обратный вызов и создать собственное обещание.
.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
}
};
});
};
Я бы предпочел второе решение, потому что оно более простое.
Я тоже столкнулся с этой проблемой, и вот что сработало для меня. Добавьте преобразователь ответа, который получит результат массива и создаст объект ресурса вручную, что, как я предполагаю, 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;
}
},
});
К настоящему времени это еще старше, но мне удалось решить это на одной фабрике ресурсов:
.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;
})