I'm trying to build a model that dynamically updates Session variables in a Meteor project. I know that plain JSON should not be stored within backbone models, so I have a Special model set up like so:
initialize : function () {
// Log the changed properties
this.on('change', function (model, options) {
for ( var i in options.changes)
this.display(i);
Session.set('NewSpecial', model);
});
},
//Attributes
defaults: {
"Product" : null,
"ShortDescription" : null,
"Category" : "food",
"Price" : new PriceModel,
"Date" : new DateModel,
"Uses" : 0,
"Tags" : [],
"Contributor" : null
},
With "Price" and "Date" being stored in their own models:
//Price model for use within Special
var PriceModel = Backbone.Model.extend({
defaults : {
"Regular" : null,
"Special" : null,
"PercentOff" : null
}
});
//Date model for use within Special
var DateModel = Backbone.Model.extend({
defaults : {
"StartTime" : null,
"EndTime" : null,
"HumanTimeRange" : null
}
});
As shown, when the attributes of the Special model change, it should call display for the attribute that changed, and then set the Session var to the model. If my DateModel or PriceModel change however, it doesn't appear to trigger a change event on the Special model. Should each "DateModel" and "PriceModel" have their own this.on('change', ...)
methods that call Special.set(attribute, thisModel)
methods? Or is there a different way to go about this?
I see a couple problems.
First of all, your
defaults
:That will end up with one
PriceModel
, oneDateModel
, and one tags array being shared by all instances of that model. Adefaults
object is shallow copied and merged into the model's attributes, none of the values indefaults
are cloned or duplicated, they're just copied over as-is. If you want distincedPrice
,Date
, andTags
values then use a function fordefaults
:The second problem is that
set
has a fairly simplistic view of what change means. If you have a look at the source forset
, you'll see this:The
_.isEqual
won't recognize that something has changed inside yourPrice
orDate
or that you've added or removed something fromTags
. If you do things like this:then
m
will noticed thatPrice
has changed but if you:then
m
won't recognize thatPrice
has changed; your model won't automatically bind to events onPrice
so it won't notice thep.set(...)
call and it won't recognizem.set('Price', p)
as a change since that's little more than a fancy way of sayingp = p
.You can solve part of this change problem by not giving
set
aTags
array that came fromget
; make a copy, change the copy, and then hand the updated copy toset
. The half can be handled by binding to"change"
events on the containedPrice
andDate
models and forwarding them similar to how collections do it, something like this:You'd want to provide your own
set
implementation in case someone did aset('Price', some_new_object)
and you need to rebind your forwarder.