Before showing a possible solution let me tell you to consider if individual nested attribute changes are really neccessary. Updating the view upon feature changes might not cost that much time as you've to worry about.
If only one view requires to detect attribute changes in nested model attributes, maybe listening to the change event is enough since you're able to detect changes of individual attributes upon the change event.
The following solutions require you to update the whole attribute like this:
model.set("feature1", _.extend({ }, model.get("feature1"), { enabled: false }));
Please also refer to this good answer to a similar question.
When a Model's change occures, the event gets three aguments: the model, the changed values and the options to set()
and the Model stores the previous values - in your case an object of objects - in _previousAttributes
.
model.on("change:feature1", function(model, value) {
var prev = model._previousAttributes;
if (model.get("feature1").enabled !== prev.feature1.enabled) {
// update upon change of "enabled"
}
if (model.get("feature1").default !== prev.feature1.default) {
// update upon change of "default"
}
});
Since this code is a bit bulky for every "feature" you can write a separate helper:
// returns an object which maps a key difference to true to easily check
// using "key" in obj
function objDiff(a, b) {
var keys = _.union(_.keys(a), _.keys(b)), isDef = {};
_.each(keys, function(key) {
if (a[key] !== b[key]) {
isDef[key] = true;
}
});
return isDef;
}
And check for the attribute change this way:
model.on("change:feature1", function(model, value) {
var changed = objDiff(model.get("feature1"), model._previousAttributes.feature1);
if ("enabled" in changed) {
// update upon change of "enabled"
}
if ("default" in changed) {
// update upon change of "default"
}
});
Both implementations will also work if you're listening to change
only.
Side note: since your question asks for change handlers on certain attributes I assume that you're listening to individual attributes and update parts of the view individually. Consider splitting your model into a map, list or Backbone Collection of Models which only have enabled
and default
and featurename
attributes. Your view can then render and update upon "featureModelX" changes.
var FeatureModel = Backbone.Model({
defaults: {
enabled: false,
default: false
}
});
new FeatureModel({feature: "feature1"});