All answers suggesting listening for changes (using events) are correct unless you pass { silent: true } option. In that case you need to overwrite default set method in order to save attributes that has changed, and reset that list after calling save method.
MidnightLightning's answer is not correct. If you call set method twice then changedAttributes will return only the attributes that has change since last set call - it's in Backbone documentation:
changedAttributesmodel.changedAttributes([attributes])
Retrieve a hash of only the model's attributes that have changed since the last set, or false if there are none.
In my case I solved the problem with this code:
(function(_, Backbone) {
'use strict';
var _set = Backbone.Model.prototype.set,
_save = Backbone.Model.prototype.save;
_.extend(Backbone.Model.prototype, {
set: function(key, val, options) {
var options = this._getOptions(key, val, options),
toReturn = _set.call(this, key, val, options);
if(!_.isUndefined(options) && options.silent && !!this.changedAttributes()) {
this.silentChanges = _.extend([], this.silentChanges);
[].push.apply(this.silentChanges, _.keys(this.changedAttributes()));
}
return toReturn;
},
save: function(key, val, options) {
var options = this._getOptions(key, val, options),
toReturn = _save.call(this, key, val, options);
if(!_.isUndefined(options) && options.triggerSilents) {
this.triggerSilentChanges();
}
return toReturn;
},
unset: function(key, options) {
if(!_.isUndefined(options) && options.silent) {
this.silentChanges = _.extend([], this.silentChanges, _.keys(this.changedAttributes()));
}
},
triggerSilentChanges: function() {
if(!_.isEmpty(this.silentChanges)) {
var that = this;
_.each(this.silentChanges, function(key) {
that.trigger('change:' + key);
that.silentChanges = _.without(that.silentChanges, key);
});
Backbone.Model.prototype.trigger.call(this, 'change');
}
},
_getOptions: function(key, val, options) {
if(key == null || _.isObject(key)) {
return val;
}
return options;
}
});
})(_, Backbone);
If I want to get all changed attributes I use silentChages property inside the model.
If I want to trigger event for all set/unset attributes when I save I add 'triggerSilents: true' option. I can also manually trigger all changes event by calling triggerSilentChanges method.