我正在尝试构建一个动态更新Meteor项目中的Session变量的模型。我知道普通的JSON不应该存储在骨干模型中,所以我有一个特殊的模型设置如下:
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
},
“价格”和“日期”存储在他们自己的模型中:
//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
}
});
如图所示,当Special模型的属性发生更改时,应调用显示的更改属性,然后将Session var设置为模型。但是,如果我的DateModel或PriceModel发生更改,则它似乎不会触发Special模型上的更改事件。每个“DateModel”和“PriceModel”都应该有自己的this.on('change', ...)
方法来调用Special.set(attribute, thisModel)
方法吗?或者有不同的方法可以解决这个问题吗?
答案 0 :(得分:2)
我看到了几个问题。
首先,您的defaults
:
defaults: {
"Product" : null,
"ShortDescription" : null,
"Category" : "food",
"Price" : new PriceModel,
"Date" : new DateModel,
"Uses" : 0,
"Tags" : [],
"Contributor" : null
}
最终会有一个PriceModel
,一个DateModel
,并且该模型的所有实例都会共享一个标记数组。一个defaults
对象被浅层复制并合并到模型的属性中,defaults
中没有任何值被克隆或复制,它们只是按原样复制。如果您想要区分Price
,Date
和Tags
值,请使用defaults
的函数:
defaults: function() {
return {
"Product" : null,
"ShortDescription" : null,
"Category" : "food",
"Price" : new PriceModel,
"Date" : new DateModel,
"Uses" : 0,
"Tags" : [],
"Contributor" : null
};
}
第二个问题是set
对更改的含义有一个相当简单的看法。如果你看一下source for set
,你会看到:
// If the new and previous value differ, record the change. If not,
// then remove changes for this attribute.
if (!_.isEqual(prev[attr], val) || (_.has(now, attr) !== _.has(prev, attr))) {
this.changed[attr] = val;
if (!silent) this._pending[attr] = true;
} else {
delete this.changed[attr];
delete this._pending[attr];
if (!changing) delete this._changes[attr];
}
_.isEqual
无法识别您Price
或Date
内的某些内容发生了变化,或者您已从Tags
添加或删除了某些内容。如果你做这样的事情:
p = new PriceModel(...);
m.set('Price', p)
然后m
会注意到Price
已更改,但如果您:
p = m.get('Price');
p.set(...);
m.set('Price', p);
然后m
无法识别Price
已发生变化;您的模型无法自动绑定到Price
上的活动,因此它不会注意到p.set(...)
来电,因此无法识别m.set('Price', p)
作为更改#39;仅仅是一种说p = p
的奇特方式。
您可以通过不set
来自Tags
的{{1}}数组来解决部分此更改问题;制作副本,更改副本,然后将更新的副本交给get
。可以通过绑定到包含的set
和"change"
模型上的Price
事件来处理这一半,并将其转发类似于集合的执行方式,如下所示:
Date
您希望提供自己的initialize: function() {
this.attributes.Price.on(
'all',
function(ev, model, opts) { this.trigger(ev, model, opts) },
this
);
//...
}
实施,以防某人执行set
并且您需要重新绑定转发器。