Last active
October 6, 2015 21:37
-
-
Save philfreo/3056724 to your computer and use it in GitHub Desktop.
Backbone Model mutators / computed properties
This file contains 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
var Model = Backbone.Model.extend({ | |
/** | |
* Override main attribute getter to handle mutators. | |
* Looks for an object on the model called 'mutators', keyed by key name, | |
* with values of either the getter function or an object like: | |
* { get: function() {}, set: function() {} } | |
*/ | |
get: function(attr) { | |
var val, | |
mutator = this.mutators && this.mutators[attr]; | |
if (mutator) { | |
mutator = _(mutator).isFunction() ? mutator : mutator.get; | |
return mutator.apply(this, arguments); | |
} else { | |
return this._super.apply(this, arguments); | |
} | |
}, | |
/** | |
* Override main setter function to handle mutators that have a setter. | |
* See "get" above for details. | |
* example: | |
* mutators: { | |
* full_name: { | |
* get: function() { return this.get('first_name') + ' ' + this.get('last_name'); }, | |
* triggers: ['first_name', 'last_name'] // trigger change:full_name whenever these 2 fields are changed | |
* } | |
* } | |
*/ | |
set: function(key, value, options) { | |
options = options || (options = {}); | |
// we could first figure out which keys are mutators which will get | |
// re-set below in the loop and pull them out from getting set unnecessarily first | |
// by super. doesn't seem to matter for now though. | |
this._super.apply(this, arguments); | |
// since key can be string or object | |
if (_.isObject(key) || key === null) { | |
attrs = key; | |
options = value; | |
} else { | |
attrs = {}; | |
attrs[key] = value; | |
} | |
// see if we're setting any mutators that have a 'set' function | |
// the mutator setter functions should pass a {fromMutator: true} option when it does its own setting | |
if (!options || !options.fromMutator) { | |
_(attrs).each(function(value, key) { | |
// get the setter mutator function if it exists for this attribute/key | |
var mutator = this.mutators && this.mutators[key] && _(this.mutators[key].set).isFunction() && this.mutators[key].set; | |
if (mutator) { | |
mutator.call(this, key, value, { silent: true }); | |
} | |
if (!options || !options.silent) { | |
// see if we're changing (without silent) and attributes listed in the 'triggers' section of any mutator | |
// if so that means that the model should trigger a change:mutator_name | |
if (this.mutators) { | |
_(this.mutators).each(function(mutator, mutatorName) { | |
if (mutator.triggers && _(mutator.triggers).indexOf(key) !== -1) { | |
// we're setting a key that should trigger a change:mutator_name | |
// HACK. we probably would want to just directly call this.trigger('change:mutator_name') | |
// but that doesn't work if something binds just on 'change' (e.g., Backbone.ModelBinder) | |
// so we do a real "set" on this computed attribute | |
// but then immediately unset it (silently) since we don't really want to keep it around | |
this.set(mutatorName, this.get(mutatorName)); | |
this.unset(mutatorName, { silent: true }); | |
} | |
}, this); | |
} | |
} | |
}, this); | |
} | |
return this; | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: this code relies on https://github.com/lukasolson/Backbone-Super but could be easily tweaked to not use it.