1

I am trying set up loading for my Angular app so that when somebody goes to page 2, page 3 will load in the background.

I am using $resource to query Posts with Post.query(). Post.query({page: 1}) gets an array of post records with ID's 0-9.

My actual Post controller accepts parameters which specifies page: posts.json?page=1 where each page has 10 posts.

So Basically I want to query page 1 and page 2 on load and then concatenate them as:

$scope.visiblePosts. When a user is on page 2 I then want page 3 to load in the background and to concatenate page 3 with $scope.visiblePosts.

For pagination I am using the following code:

View:

<div ng-repeat="post in filtered = visiblePosts |
 startFrom:(currentPage-1)*pageSize | limitTo:pageSize | orderBy:order:true">

App:

app.filter("startFrom", function() {
  return function(input, start) {
    if (input) {
      start = +start;
      return input.slice(start);
    }
    return [];
  };
});

Controller:

$scope.currentPage = 1;

$scope.pageSize = 10;

$scope.noOfPages = Math.ceil($scope.posts.length / $scope.pageSize);

$scope.noPrev = function() {
  return $scope.currentPage === 1;
};

$scope.noNext = function() {
  return $scope.currentPage === $scope.noOfPages;
};

$scope.prevPage = function() {
  return $scope.setPage($scope.currentPage - 1);
};

$scope.nextPage = function() {
  return $scope.setPage($scope.currentPage + 1);
};

$scope.setPage = function(pageNo) {
  return $scope.currentPage = pageNo;
};

$scope.filter = function() {
  return window.setTimeout((function() {
    return $scope.noOfPages = Math.ceil($scope.filtered.length / $scope.pageSize);
  }), 10);
};

$scope.$watch("currentPage", $scope.setPage);

Any help is greatly appreciated, nothing seems to be working. I've tried concat() already and a few other things.

godzilla3000
  • 246
  • 3
  • 23
  • Where do you query posts in your controller? What is `visiblePosts` and where it is defined? Could you share code for `Post` service? What exactly does not work? If there are any errors in console? – Alexey Nov 22 '13 at 06:24
  • Everything is clearly written. The Posts query returns everything correctly, visible posts is a scope variable which contains the retrieved collection. The concatenation does not work, there are no errors in the console. – godzilla3000 Nov 22 '13 at 18:43
  • Many people could help you even without bounty, if it weren't in CoffeScript: http://blog.ponyfoo.com/2013/09/28/we-dont-want-your-coffee – Adam Nov 23 '13 at 20:36

1 Answers1

2

First of all, never modify your scope outside Angular digest cycle. Forget about setTimeout and setInterval. Instead, use $timeout and $interval built-in services. In your case, you should try $evalAsync: AngularJS : $evalAsync vs $timeout

Also $scope.$watch("currentPage", $scope.setPage) makes no sense to me.

And finally, to the point: the controller (and so the scope) is instantiated every time you navigate to the next page, so you can't keep the data in your scope across different pages.

Unlike controllers, services are singletons, instantiated only once and never destroyed.

You should create a service that keeps already loaded posts and preloads next pages. Your controller should ask this service for only the page it needs to display.

The additional benefit o this approach is that you no longer need filters.

You can also use a cache from $cacheFactory to keep the data, or just use the cache option of the $resource service. Then you would just preload the next page after showing the current page, so the next time it would be loaded immediately from the cache.

Example:

function MyController($scope, $resource) {

    var res = $resource("/posts.json", {}, {
        query: {
            method: 'GET',
            isArray: true,
            // enable caching:
            cache: true
        }
    });

    $scope.currentPage = 1;

    $scope.$watch("currentPage", function() {
        $scope.posts = res.query({
            page: $scope.currentPage
        });
        // precache the next page:
        res.query({
            page: $scope.currentPage + 1    
        });
    });

}

...

<div ng-repeat="post in posts">
Community
  • 1
  • 1
Adam
  • 2,897
  • 2
  • 23
  • 23
  • this is a one page application though – godzilla3000 Nov 24 '13 at 17:14
  • those pages represent sections of a collection to display in my one page app – godzilla3000 Nov 24 '13 at 17:14
  • Almost every Angular-powered website is a Single Page Application (aka SPA). So, do you mean just SPA, or that all pages have the same URL? Anyway, whether you keep the state in service or scope, using `cache: true` in your `$resource` is probably the simplest solution. – Adam Nov 24 '13 at 17:31
  • But wouldn't this require querying the entire collection? that would slow load time – godzilla3000 Nov 25 '13 at 02:47
  • Why entire collection? See my answer, I've added an example. – Adam Nov 25 '13 at 13:57
  • The example is not for adding the new result after the previous, this overwrites the previous page's data – Peter Mar 12 '19 at 17:01