Skip to content

Instantly share code, notes, and snippets.

@tgriesser
Created August 16, 2012 15:47
Show Gist options
  • Save tgriesser/3371206 to your computer and use it in GitHub Desktop.
Save tgriesser/3371206 to your computer and use it in GitHub Desktop.
backbone model change
// Returns a hash of attributes whose current and previous value differ.
_changed : function(){
var attr, changes = {},
now = this.attributes,
old = this._previousAttributes || {};
var all = _.union(_.keys(now), _.keys(old));
// If the new and current value differ, record the change.
for (var i = all.length; i>=0; i--) {
attr = all[i];
if (!_.isEqual(now[attr], old[attr]) || (_.has(now, attr) != _.has(old, attr))) {
changes[attr] = now[attr];
}
}
return changes;
},
// Set a hash of model attributes on the object, firing `"change"` unless
// you choose to silence it.
set: function(key, value, options) {
var attrs, attr, val
now = this.attributes;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (_.isObject(key) || key == null) {
attrs = key;
options = value;
} else {
attrs = {};
attrs[key] = value;
}
// Extract attributes and options.
options || (options = {});
if (!attrs) return this;
if (attrs instanceof Model) attrs = attrs.attributes;
if (options.unset) for (attr in attrs) attrs[attr] = void 0;
// Run validation.
if (!this._validate(attrs, options)) return false;
// Check for changes of `id`.
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
// For each `set` attribute...
for (attr in attrs) {
delete this._escapedAttributes[attr];
// Update or delete the current value.
options.unset ? delete now[attr] : now[attr] = attrs[attr];
}
// Fire the `"change"` events.
if (!options.silent) this.change(options);
return this;
},
// Call this method to manually fire a `"change"` event for this model and
// a `"change:attribute"` event for each changed attribute.
// Calling this will cause all objects observing the model to update.
change: function(options) {
var change,
changed = this._changed(),
changing = this._changing;
this._changing = true;
for (change in changed) {
this.trigger('change:' + change, this, changed[change], options || {});
}
if (changing) return this;
if (!_.isEmpty(changed)) this.trigger('change', this, options);
this._changing = false;
this._previousAttributes = _.clone(this.attributes);
return this;
},
// Determine if the model has changed since the last `"change"` event.
// If you specify an attribute name, determine if that attribute has changed.
hasChanged: function(attr) {
var changed = this._changed();
if (attr == null) return !_.isEmpty(changed);
return _.has(changed, attr);
},
// Return an object containing all the attributes that have changed, or
// false if there are no changed attributes. Useful for determining what
// parts of a view need to be updated and/or what attributes need to be
// persisted to the server. Unset attributes will be set to undefined.
// You can also pass an attributes object to diff against the model,
// determining if there *would be* a change.
changedAttributes: function(diff) {
var changed = this._changed();
if (!diff) return !_.isEmpty(changed) ? changed : false;
var val, changes = false, old = this._previousAttributes;
for (var attr in diff) {
if (_.isEqual(old[attr], (val = diff[attr]))) continue;
(changes || (changes = {}))[attr] = val;
}
return changes;
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment