Last active
April 26, 2016 19:33
-
-
Save th3hunt/05da2bb6b6cef7153f807035029637cd to your computer and use it in GitHub Desktop.
A mixin that enables special kind of computed properties on backbone models
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Backbone Computed | |
* ----------------- | |
* | |
* a mixin that enables special kind of computed properties on backbone models | |
* | |
* | |
*/ | |
(function (root, factory) { | |
if (typeof exports !== 'undefined') { | |
module.exports = factory(require('backbone'), require('underscore')); | |
} else { | |
factory(root.Backbone, root._); | |
} | |
}(this, function (Backbone, _) { | |
var Computed = { | |
/** | |
* Create an attribute that gets computed from the selected model of a Backbone.Select.One collection | |
* | |
* @param {string} attributeName - the attribute name | |
* @param {Backbone.Collection} collection - a Backbone.Select.One collection | |
* @param {object} [options] - the compute options | |
* @param {boolean} [options.bidirectional=false] - whether any direct change to the attribute will be reflected on the collection | |
* @param {*} [options.noneValue=null] - the attribute value for when no model is selected | |
* @param {string|function} [options.map='id'] - map the the selected model to a value | |
* @param {string} [options.selectOn='sync reset'] - collection events on which to set the selected model based on the computed attribute | |
* | |
* selectOn option is specially useful when the model is initialized with a value for the computed attribute, | |
* and the collection is then loaded asynchronously. In general, it lets us select a model on the collection | |
* when the collection emits one or more events of our choosing. | |
* | |
* @example | |
* this.computeFromSelected('job_title', this.collection, {noneValue: 'All Jobs', map: 'title'}); | |
* | |
*/ | |
computeFromSelected: function (attributeName, collection, options) { | |
var defaults = { | |
bidirectional: false, | |
map: 'id', | |
noneValue: null, | |
selectOn: 'sync reset' | |
}; | |
options = _.defaults(options || {}, defaults); | |
function modelToValue(model) { | |
try { | |
return _.isString(options.map) ? model.get(options.map) : options.map(model); | |
} catch (e) { | |
return model.id; | |
} | |
} | |
function compute() { | |
var model = collection.selected; | |
this.set(attributeName, model ? modelToValue(model) : options.noneValue); | |
} | |
function reverse() { | |
var model = collection.find(function (m) { | |
return modelToValue(m) === this.get(attributeName); | |
}.bind(this)); | |
if (model) { | |
collection.select(model); | |
} | |
} | |
this.listenTo(collection, 'deselect:one select:one', compute); | |
if (options.selectOn) { | |
this.listenTo(collection, options.selectOn, reverse); | |
} | |
if (options.bidirectional) { | |
this.listenTo(this, 'change:' + attributeName, reverse); | |
} | |
} | |
}; | |
_.extend(Backbone.Model.prototype, Computed); | |
return Computed; | |
})); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment