Skip to content

Instantly share code, notes, and snippets.

@miraculixx
Created April 17, 2014 13:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miraculixx/dd36af38bf99d592444b to your computer and use it in GitHub Desktop.
Save miraculixx/dd36af38bf99d592444b to your computer and use it in GitHub Desktop.
Add a Django-like filter to Backbone Models and Collections
/**
* Backbone filter. This adds a filtering mechanism
* similar to Django ORM filters:
*
* var MyModel = Backbone.Model.extend(...);
* var model = new MyModel(...);
* model.filter("somekey", "somevalue");
* model.filter("anotherkey", "anothervalue");
* Doing so will result in the query() method to
* return a query string of all filters:
*
* somekey=somevalue&anotherkey=anothervalue
*
* Note that if the key is an instande of Backbone.Model
* you can take another model as the key and the query()
* method will translate this to get the id attribute
* as the value and the Model's name as the key, e.g.
*
* var MyModel = Backbone.Model.extend(...);
* var User = Backbone.Model.extend({ ..., asFilter : 'user', ...});
* var model = new MyModel(...);
* var user = new User({id : 1})).fetch();
* model.filter(user);
* model.query();
* => user=1
*
* Notes:
* (1) for this to work, the Model must specify the asFilter
* attribute. asFilter can be a value or a function.
* (2) the get('id') call to get the key value of the filter
* is called by filter() not by query(). If you want to
* override this, pass a function, which will be evaluated
* by query(), that is possibly much later then the filter
* is defined. Use this if you want the filter to adapt
* dynamically.
*
* Use the query() function to construct the URL:
*
* ...
* url : function() {
* return this.urlRoot + "?" + this.query();
* }
* ...
*/
var Filter = {
/**
* add a filter
*
* @param key string or instance of a Backbone.Model
* @param value string or function. functions are evaluated
* at query() time
* @param op undefined or Django tastypie operator
* @return this for chainable calls
*/
filter : function(key, value, op) {
if(key instanceof $B.Model) {
value = _.isFunction(value) ? value : key.get('id');
key = _.isFunction(key.asFilter) ? key.asFilter() : key.asFilter;
}
this._filters[key + (op ? '__' + op : '')] = value;
return this;
},
/**
* clear all filters. Note this does not affect the
* current state of the model, it only takes effect upon
* the next sync() call
*/
clearFilter : function() {
this._filters = {};
}
/**
* returns true if one or more filters have been applied
* false otherwise
*/
filtered : function() {
return this.keys(_filters).length > 0;
},
/**
* return the current set of filters as a dictionary
* of key/value pairs
*/
getFilter : function() {
return this._filters();
},
/**
* dict of filters, value can be a function
* or a string:
* {
* key : value,
* key2 : function() { ... }
* }
*/
_filters : {},
/**
* return the URL's query string. This method
* used by the default url() (see tastypie.js)
* @return filters as term=value&term2=value2
*/
query : function() {
// create the list of filters as key value pair
var queryfilters = [];
for (var key in this._filters) {
var value = _.isFunction(this._filters[key]) ? this._filters[key](this) : this._filters[key];
queryfilters.push("{0}={1}".format([key, value]));
};
// return the query string
return queryfilters.join('&');
}
};
_.extend($B.Model.prototype, Filter);
_.extend($B.Collection.prototype, Filter);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment