0

I'm trying to create an interactive photo database where the user can sort through photos and filter by user, check multiple categories he or she is interested in, and sort the filtered data by date, number of favorites, etc. The filter/sorting criteria are selected by the user on the DOM and are stored from the client side to $scope.model. The quantity of data visible to the user would be controlled with infinite scroll.

I've created a repository of this example, and I've deployed it here. I've reproduced some of the relevant code from scroll.controller.js below:

Code

// infinite-scroll logic & collection subscription //
$scope.currentPage = 1;
$scope.perPage = 12;
$scope.orderProperty = '-1';
$scope.query = {};

$scope.images = $scope.$meteorCollection(function() {
  query={};            
  // if filtered by a user...
  if ($scope.getReactively('model.shotBy')) {
    query.shotBy = $scope.model.shotBy;
  };
  // if category filter(s) are selected...
  if ($scope.getReactively('model.category', true)) {
    if ($scope.model.category.length > 0){
      var categories = [];
      for (var i=0; i < $scope.model.category.length; i++){            
        categories.push($scope.model.category[i]);
      }
      query.category = {$in: categories};
    }
  };
  $scope.currentPage = 1; // reset
  return Images.find(query, { sort: $scope.getReactively('model.sort')});
});

$meteor.autorun($scope, function() {
  if ($scope.getReactively('images')){
    $scope.$emit('list:filtered');    
  }
});

$meteor.autorun($scope, function() {
  $scope.$meteorSubscribe('images', {
    limit: parseInt($scope.getReactively('perPage'))*parseInt(($scope.getReactively('currentPage'))),
    skip: 0,
    sort: $scope.getReactively('model.sort')
  });
});              

$scope.loadMore = function() {
  // console.log('loading more');
  $scope.currentPage += 1;
};  

Problem

I can scroll through the images fine, and the infinite-scroll feature seems to work. However, when I attempt to filter the images from the DOM, the only filtered results are those which were initially visible before scrolling, and scrolling doesn't make the rest of the images that meet the criteria show, despite using $scope.$emit to signal ngInfiniteScroll to load more (documentation).

EDIT: If the initial filtered list does, in fact, reach the bottom, scrolling will append properly. It seems to not append only if the initial filtered list doesn't reach the bottom of the screem.

Question

What can I change to make ngInfiniteScroll behave as I would expect on a filtered collection?

Any help, thoughts, or suggestions would be appreciated, and let me know if there's anything else you'd like to see. Thank you!

aliigleed
  • 366
  • 2
  • 13

1 Answers1

0

Well, it took almost all day to figure out, but I now have a working example at this Github repository and deployed here.

To summarize, I found I need to filter at both the collection and subscription levels to cause perPage to apply properly and for ngInfiniteScroll functioning. Also, I needed to send an event via $scope.$emit to ngInfiniteScroll to tell it to fire again in case the images array was too small and didn't reach the edge of the screen. See the Github repository for more details, if you're interested.

Updated relevant code

// infinite-scroll logic & collection subscription //
$scope.currentPage = 1;
$scope.perPage = 12;
$scope.query = {};

function getQuery(){
  query={};            
  // if filtered by a user...
  if ($scope.getReactively('model.shotBy')) {
    query.shotBy = $scope.model.shotBy;
  };
  // if category filter(s) are selected...
  if ($scope.getReactively('model.category', true)) {
    if ($scope.model.category.length > 0){
      var categories = [];
      for (var i=0; i < $scope.model.category.length; i++){            
        categories.push($scope.model.category[i]);
      }
      query.category = {$in: categories};
    }
  };
  return query;
}

$meteor.autorun($scope, function(){
  $scope.images = $scope.$meteorCollection(function() {
    $scope.currentPage = 1; // reset the length of returned images
    return Images.find(getQuery(), { sort: $scope.getReactively('model.sort')});
  });
  $scope.$emit('filtered'); // trigger infinite-scroll to load in case the height is too small 
});

$meteor.autorun($scope, function() {
  $scope.$meteorSubscribe('images', {
    limit: parseInt($scope.getReactively('perPage'))*parseInt(($scope.getReactively('currentPage'))),
    skip: 0,
    sort: $scope.getReactively('model.sort'),
    query: getQuery()
  });
});              

$scope.loadMore = function() {
  // console.log('loading more');
  $scope.currentPage += 1;
};         

I'm not sure if I've used best practices with this answer, so please feel free to chime in with suggestions.

aliigleed
  • 366
  • 2
  • 13