Skip to content

Instantly share code, notes, and snippets.

@arendjr
Created November 23, 2013 13:59
Show Gist options
  • Save arendjr/7614919 to your computer and use it in GitHub Desktop.
Save arendjr/7614919 to your computer and use it in GitHub Desktop.
Laces.js-based Collection implementation
/**
* Base class for all collections.
*/
var Collection = Model.extend({
constructor: function() {
Model.apply(this, arguments);
/**
* The number of models in the collection.
*/
this.length = 0;
/**
* The limit to use during fetching.
*/
this.limit = 10;
/**
* The collection's models.
*/
this.models = new Laces.Array();
this.models.on("add remove", _.bind(this._updateLength, this));
/**
* The offset to use during fetching.
*/
this.offset = 0;
},
/**
* Class to use for wrapping the collection's models.
*/
ModelClass: null,
/**
* Adds a model to the collection. Does nothing if a model with the same ID is already
* in the collection.
*
* @param model A Model instance, or a set of attributes that will be wrapped in a model.
*/
add: function(model) {
if (!this.any({ id: model.id })) {
if (model instanceof this.ModelClass) {
// good
} else {
model = new this.ModelClass(this.application, model);
}
this.models.push(model);
}
},
/**
* Returns the model at the specified index.
*/
at: function(index) {
if (index >= 0 && index < this.length) {
return this.models[index];
} else {
throw new RangeError("Invalid index: " + index);
}
},
defaults: {
numItems: 0
},
fetch: function() {
var self = this;
var promise = Model.prototype.fetch.apply(this, arguments);
promise.then(function() {
_.each(self.items, function(item) {
var model = new this.ModelClass(this.application, item);
this.models.push(model);
}, self);
self.unset("items");
});
return promise;
},
/**
* Stops observing an event.
*
* @param event Name of the observed event. May be a space-separated list of event names.
* @param callback Callback function that was executed when the event fired.
*/
off: function(event, callback) {
this.models.off(event, callback);
},
/**
* Starts observing an event.
*
* @param event Name of the event to observe. May be a space-separated list of event names.
* @param callback Callback function to execute when the event fires.
*/
on: function(event, callback) {
this.models.on(event, callback);
},
/**
* Removes a model from the collection. Does nothing if the model is not found in the
* collection.
*
* @param model A Model instance, or a model ID.
*/
remove: function(model) {
var index;
if (model instanceof this.ModelClass) {
index = this.indexOf(model);
} else {
index = this.findIndex({ id: model });
}
if (index > -1) {
this.models.remove(index);
}
},
url: function() {
var url = Model.prototype.url.call(this);
return url + "?" + $.param({ limit: this.limit, offset: this.offset });
},
_updateLength: function() {
this.length = this.models.length;
}
});
// mixin useful LoDash methods
_.each(["any", "each", "filter", "find", "findIndex", "reject"], function(func) {
Collection.prototype[func] = function(callback, context) {
return _[func](this.models, callback, context || this);
};
});
// mixin useful Array methods
_.each(["indexOf", "push", "shift", "slice", "splice", "unshift"], function(func) {
Collection.prototype[func] = function() {
return this.models[func].apply(this.models, arguments);
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment