I have an angularjs app working nicely with django-rest but have hit an issue by introducing pagination. I have a restservice and controller as per the below
// restservices.js
// API call for all images in an event
services.factory('ImageEvent', function ($resource) {
return $resource(rest_api + '/rest/image/?event_id=:eventId&format=json', {}, {
query: { method:'GET', params:{eventId:''}, isArray:true}
})
});
// controllers.js
// all Images in an event
.controller('ImageEventCtrl', ['$scope', '$stateParams', 'ImageEvent', function($scope, $stateParams, ImageEvent) {
$scope.images = ImageEvent.query({eventId: $stateParams.eventId}, function(images) {
});
}])
this returns the following json
[
{
"id": 13,
"title": "01-IMG_4953.JPG",
},
{
"id": 14,
"title": "02-IMG_4975.JPG",
},
{
"id": 15,
"title": "03-IMG_4997.JPG",
}
]
However if I turn on django-rest pagination it returns the following json:
{
"count": 3,
"next": "/rest/image/?event_id=1&page=2",
"previous": null,
"results":
[
{
"id": 13,
"title": "01-IMG_4953.JPG",
},
{
"id": 14,
"title": "02-IMG_4975.JPG",
}
]
}
This change has caused the following console error and everything fails to work:
Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an array but got an object
Changing the restservice to isArray:false has made no difference. Can my controller be re-written to cope with this and in a perfect world also expose the count, next and previous links?
Thanks
Angular-ui has a pagination directive that I've used with Django Rest Framework before.
http://angular-ui.github.io/bootstrap/#/pagination
To load only X amount of items at a time I have done the following below. Note that I'm using the pagination to recreate the django admin feature in angular.
if request.GET.get('page'):
# Get the page number
page = request.GET.get('page')
# How many items per page to display
per_page = data['admin_attrs']['list_per_page']
begin = (int(page) - 1) * per_page
end = begin + per_page
objects = MODEL.objects.all()[begin:end]
# Serializer for your corresponding itmes. This will grab the particular modelserializer
serializer = serializer_classes[MODEL._meta.object_name](
objects, fields=admin_attrs['list_display']
)
data['objects'] = serializer.data
return Response(data)
My angular code to keep track of page and also allow back button functionality and also update the URL:
modelDetails Factory gets generates the url with the correct page number from pagination
app.factory('modelDetails', function($http, $q){
data = {content: null}
var dataFactory = {}
dataFactory.getObjects = function (app, model, page){
var deferred = $q.defer()
$http.get('api/admin/' + app + '/' + model + '/?page=' + page)
.success(function(result) {
deferred.resolve(result);
});
return deferred.promise
};
return dataFactory
});
$scope.loadObjects = function () {
modelDetails.getObjects(app, model, $scope.currentPage)
.then(function (data){
$scope.headers = data.headers;
$scope.admin_attrs = data.admin_attrs;
blank = new Array()
list_display = data.admin_attrs.list_display
$scope.objects = convertObjects(data.objects, list_display)
$scope.numPerPage = data.admin_attrs.list_per_page
$scope.currentPage = $stateParams.p
$scope.maxSize = 20;
$scope.bigTotalItems = data.object_count;
$scope.numPages = Math.ceil(data.object_count / $scope.admin_attrs.list_per_page);
})
.then( function (data) {
$scope.$watch('currentPage + numPerPage', function(oldVal, newVal) {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
, end = begin + $scope.numPerPage;
if(oldVal != newVal){
$location.search('p', $scope.currentPage)
}
$rootScope.$on('$locationChangeSuccess', function(event) {
$scope.currentPage = $location.search().p
modelDetails.getObjects(app, model, $scope.currentPage)
.then( function (data) {
// convertObjects just reorders my data in a way I want
$scope.objects = convertObjects(data.objects, list_display)
});
});
});
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With