diff --git a/README.md b/README.md index b77dff2d7..dff4d4f27 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,15 @@ angular-meteor provides an AngularJS service called $collection, which is a wrap | model | String | The name of the model that the collection will be bound to. | Yes | | | auto | Boolean | By default, changes in the model will not automatically update the collection. However if set to true, changes in the client will be automatically propagated back to the collection. A deep watch is created when this is set to true, which will degrade performance. | No | false | | publisher | Boolean/String | By default, bind method will not automatically subscribe to the collection. However if set to true, bind will call Meteor.subscribe on the current collection. you can also set publisher to a string and then bind will call Meteor publish with that string. | No | false | +| paginate | Boolean | By default, bind method will not automatically add support to paginate the collection. However if set to true, the bind method will also add pagination functionality to the scope. | No | false | + +Paginate will use the following scope properties to implement pagination: + +| Property | Type | Description | Required | Default | +| :------------ | :-------- | :------------------------------------------------------------------------ | :-------- | :-------- | +| perPage | Number | The number of items on each page | | +| page | Number | The current page number (1 based). A $watch is setup to re-fetch the collection on change | Yes | | + Once a collection has been bound using the bind method, the model will have access to the following methods for upserting/removing objects in the collection. If the auto argument has been set to true, then the user will not need to call these methods because these methods will be called automatically whenever the model changes. diff --git a/modules/angular-meteor-collections.js b/modules/angular-meteor-collections.js index 3974c1b73..91fd45217 100644 --- a/modules/angular-meteor-collections.js +++ b/modules/angular-meteor-collections.js @@ -11,7 +11,7 @@ angularMeteorCollections.factory('$collection', ['$q', 'HashKeyCopier', '$subscr return { bindOne: function(scope, model, id, auto, publisher) { - Deps.autorun(function(self) { + Tracker.autorun(function(self) { scope[model] = collection.findOne(id); if (!scope.$$phase) scope.$apply(); // Update bindings in scope. scope.$on('$destroy', function () { @@ -47,40 +47,69 @@ angularMeteorCollections.factory('$collection', ['$q', 'HashKeyCopier', '$subscr return deferred.promise; }, - bind: function (scope, model, auto, publisher) { + bind: function (scope, model, auto, publisher, paginate) { auto = auto || false; // Sets default binding type. if (!(typeof auto === 'boolean')) { // Checks if auto is a boolean. throw new TypeError("The third argument of bind must be a boolean."); } - Deps.autorun(function (self) { - var ngCollection = new AngularMeteorCollection(collection, $q, selector, options); + var unregisterWatch = null; - // Bind collection to model in scope. Transfer $$hashKey based on _id. - var newArray = HashKeyCopier.copyHashKeys(scope[model], ngCollection, ["_id"]); - scope[model] = updateAngularCollection(newArray, scope[model]); + var rebind = function(){ + Tracker.autorun(function (self) { - if (!scope.$$phase) scope.$apply(); // Update bindings in scope. - scope.$on('$destroy', function () { - self.stop(); // Stop computation if scope is destroyed. + if (paginate){ + options = { + limit: parseInt(scope.perPage), + skip: (parseInt(scope.page) - 1) * parseInt(scope.perPage) + }; + if (scope.sort) { options.sort = [scope.sort]; } + } + + var ngCollection = new AngularMeteorCollection(collection, $q, selector, options); + + // Bind collection to model in scope. Transfer $$hashKey based on _id. + var newArray = HashKeyCopier.copyHashKeys(scope[model], ngCollection, ["_id"]); + scope[model] = updateAngularCollection(newArray, scope[model]); + + if (!scope.$$phase) scope.$apply(); // Update bindings in scope. + scope.$on('$destroy', function () { + self.stop(); // Stop computation if scope is destroyed. + }); }); - }); - if (auto) { // Deep watches the model and performs autobind. - scope.$watch(model, function (newItems, oldItems) { - // Remove items that don't exist in the collection anymore. - angular.forEach(oldItems, function (oldItem) { - var index = newItems.map(function (item) { - return item._id; - }).indexOf(oldItem._id); - if (index == -1) { // To here get all objects that pushed or spliced - if (oldItem._id) { // This is a check to get only the spliced objects - newItems.remove(oldItem._id); + if (auto) { // Deep watches the model and performs autobind. + unregisterWatch = scope.$watch(model, function (newItems, oldItems) { + // Remove items that don't exist in the collection anymore. + angular.forEach(oldItems, function (oldItem) { + var index = newItems.map(function (item) { + return item._id; + }).indexOf(oldItem._id); + if (index == -1) { // To here get all objects that pushed or spliced + if (oldItem._id) { // This is a check to get only the spliced objects + newItems.remove(oldItem._id); + } } - } - }); - newItems.save(); // Saves all items. - }, auto); + }); + newItems.save(); // Saves all items. + }, auto); + } + }; + rebind(); + + if (paginate){ + scope.$watch("page", function(newValue, oldValue){ + if (!newValue) + return; + + if (newValue == oldValue) + return; + + if (unregisterWatch) + unregisterWatch(); + + rebind(); + }); } var deferred = $q.defer();