backbone-filtered-collection
Version:
Create a filtered version of a backbone collection that stays in sync.
82 lines (70 loc) • 2.22 kB
JavaScript
var _ = require('underscore');
// Converts a key and value into a function that accepts a model
// and returns a boolean.
function convertKeyValueToFunction(key, value) {
return function(model) {
return model.get(key) === value;
};
}
// Converts a key and an associated filter function into a function
// that accepts a model and returns a boolean.
function convertKeyFunctionToFunction(key, fn) {
return function(model) {
return fn(model.get(key));
};
}
function createFilterObject(filterFunction, keys) {
// Make sure the keys value is either an array or null
if (!_.isArray(keys)) {
keys = null;
}
return { fn: filterFunction, keys: keys };
}
// Accepts an object in the form of:
//
// {
// key: value,
// key: function(val) { ... }
// }
//
// and turns it into a function that accepts a model an returns a
// boolean + a list of the keys that the function depends on.
function createFilterFromObject(filterObj) {
var keys = _.keys(filterObj);
var filterFunctions = _.map(keys, function(key) {
var val = filterObj[key];
if (_.isFunction(val)) {
return convertKeyFunctionToFunction(key, val);
}
return convertKeyValueToFunction(key, val);
});
// Iterate through each of the generated filter functions. If any
// are false, kill the computation and return false. The function
// is only true if all of the subfunctions are true.
var filterFunction = function(model) {
for (var i = 0; i < filterFunctions.length; i++) {
if (!filterFunctions[i](model)) {
return false;
}
}
return true;
};
return createFilterObject(filterFunction, keys);
}
// Expects one of the following:
//
// - A filter function that accepts a model + (optional) array of
// keys to listen to changes for or null)
// - An object describing a filter
function createFilter(filter, keys) {
// This must go first because _.isObject(fn) === true
if (_.isFunction(filter)) {
return createFilterObject(filter, keys);
}
// If the filter is an object describing a filter, generate the
// appropriate function.
if (_.isObject(filter)) {
return createFilterFromObject(filter);
}
}
module.exports = createFilter;