5

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

1 Answer 1

3

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)    
                        });                                                                
            });                                                                            
        });                                                                                
     });                                                                                   
}                 
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks I will take a look. Any views on whether this will load the whole result set and then angular-ui paginates it? I have result sets that are so large its unworkable to load it all then slice it.
I've updated my answer. You'll have to modify based upon your needs but it's working so far for me. I'm not saying this is perfect as I'm still working on it myself.
Thanks, I didn't go exactly your route but used your code as a base to provide the pagination in my REST api instead. Really useful
Do you have a repo or somewhere I can check out the code for using django admin in angular? Right now to use the django admin I have to turn off html5 mode.
@shnek I created a repo a while ago trying to completely replicate django admin in angular but it hasn't been touched in over a year now. Use at your own will as it's far from stable. Certainly not done. I stopped right in the middle of it: github.com/austinhuminski/angular-django-admin

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.