when trying to set value for deep nested attribute of a nested model with same old value, change events still fire on parents level, no change event fire on deep attributed level
below test code, with proposed fix
(function () {
var BugModel = Backbone.NestedModel.extend({
});
var FixModel = Backbone.NestedModel.extend({
_setAttr: function (newAttrs, attrPath, newValue, opts) {
opts = opts || {};
var fullPathLength = attrPath.length;
var model = this;
var oldVal = Backbone.NestedModel.walkThenGet(newAttrs, attrPath);
// See if this is a new value being set
var isNewValue = !_.isEqual(oldVal, newValue);
Backbone.NestedModel.walkPath(newAttrs, attrPath, function (val, path, next) {
var attr = _.last(path);
var attrStr = Backbone.NestedModel.createAttrStr(path);
if (path.length === fullPathLength) {
// reached the attribute to be set
if (opts.unset) {
// unset the value
delete val[attr];
// Trigger Remove Event if array being set to null
if (_.isArray(val)) {
var parentPath = Backbone.NestedModel.createAttrStr(_.initial(attrPath));
model._delayedTrigger('remove:' + parentPath, model, val[attr]);
}
} else {
// Set the new value
val[attr] = newValue;
}
// Trigger Change Event if new values are being set
if (!opts.silent && _.isObject(newValue) && isNewValue) {
var visited = [];
var checkChanges = function (obj, prefix) {
// Don't choke on circular references
if (_.indexOf(visited, obj) > -1) {
return;
} else {
visited.push(obj);
}
var nestedAttr, nestedVal;
for (var a in obj) {
if (obj.hasOwnProperty(a)) {
nestedAttr = prefix + '.' + a;
nestedVal = obj[a];
if (!_.isEqual(model.get(nestedAttr), nestedVal)) {
model._delayedChange(nestedAttr, nestedVal, opts);
}
if (_.isObject(nestedVal)) {
checkChanges(nestedVal, nestedAttr);
}
}
}
};
checkChanges(newValue, attrStr);
}
} else if (!val[attr]) {
if (_.isNumber(next)) {
val[attr] = [];
} else {
val[attr] = {};
}
}
if (!opts.silent) {
// let the superclass handle change events for top-level attributes
if (path.length > 1 && isNewValue) {
model._delayedChange(attrStr, val[attr], opts);
}
if (_.isArray(val[attr])) {
model._delayedTrigger('add:' + attrStr, model, val[attr]);
}
}
});
}
});
$(document).ready(function () {
var bugModel = new BugModel({
Category: {
categoryId: 1,
categoryName: "Category 1",
Types: [{
typeId: 1,
typeName: "type1"
},
{
typeId: 2,
typeName: "type2"
}]
}
});
bugModel.on("change:Category.Types", function () { console.log("no actual change but bug parent change event fired"); });
bugModel.on("change:Category.Types[0].typeName", function () { console.log("fire only with correct change"); });
var fixModel = new FixModel({
Category: {
categoryId: 1,
categoryName: "Category 1",
Types: [{
typeId: 1,
typeName: "type1"
},
{
typeId: 2,
typeName: "type2"
}]
}
});
fixModel.on("change:Category.Types", function () { console.log("fix model have changed"); });
bugModel.set('Category.Types[0].typeName', "type1");
fixModel.set('Category.Types[0].typeName', "type1");
});
})();
when trying to set value for deep nested attribute of a nested model with same old value, change events still fire on parents level, no change event fire on deep attributed level below test code, with proposed fix