I have a parent Backbone Model that contains two objects.
(1) An array of Backbone Models
(2) A string
If I bind to the parent, setting the value of the string does trigger the change event, however calling set on an attribute of one of the models in the array of models does not trigger the change event on the parent.
How do I fix this so that any change to any of the models in the array triggers the parents change event?
EDIT -- Added Code by request
var myModel = Backbone.Model.extend(
{
defaults : {
models : [],
aString: 'foobar'
}
}
);
var foo = new myModel();
var arrayElement = Backbone.Model.extend({x: 7});
var arrayElement1 = new arrayElement({x: 7});
foo.set('models', [arrayElement1]);
foo.bind('change', function() { console.log('changed!')});
arrayElement1.set('x', 10); //Does not trigger console log
foo.set('aString', 'barfoo'); //Does trigger console log
Backbone models don't bind anything to their attributes so foo
has no way of knowing that you are changing one of its attributes behind its back. So, when you do this:
foo.set('models', [some_other_model]);
some_other_model.set(...);
you haven't actually changed foo
at all, all you've done is changed one of foo
's attributes directly. A model's attributes can be anything, the model simply treats them as opaque blobs. You'll have similar problems with something like this:
o = { a: 'b' };
m.set('p', o);
o.a = 'c';
In both cases, you're directly changing a model's attribute through a reference rather than through the model's interface.
Collections, on the other hand, do listen for events on their models. Collections are collections of models so they expect their members to be models and behave accordingly.
If you want a contained model to propagate 'change'
events then you'll have to do it yourself by, perhaps, overriding set
to manually bind change handlers to propagate the events. You could also use an internal collection instead of an array to make propagating the events easier.
You also have a hidden bug in your defaults
. The defaults are copied to new model instances but the copy is a shallow copy so your models will end up sharing the same reference to the array unless an explicit set
is done to replace the reference. For example, this:
var M = Backbone.Model.extend({
defaults: {
a: []
}
});
var m1 = new M();
m1.get('a').push('pancakes');
console.log(M.prototype.defaults.a);
var m2 = new M();
console.log(m2.get('a'));
will put two ['pancakes']
in the console because m1.get('a')
will return M.prototype.defaults.a
rather than a new empty array that is specific to m1
: http://jsfiddle.net/ambiguous/AraCu/
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.