Skip to content

Commit

Permalink
Add built-in support for pagination (tutorial will soon be added). th…
Browse files Browse the repository at this point in the history
…anks to @superchris
  • Loading branch information
Urigo committed Oct 28, 2014
1 parent d1584b0 commit d8304ad
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 25 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>bind</code> method, the model will have access to the following methods for upserting/removing objects in the collection. If the <code>auto</code> 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.

Expand Down
79 changes: 54 additions & 25 deletions modules/angular-meteor-collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit d8304ad

Please sign in to comment.