1

我正在尝试构建一个动态更新 Meteor 项目中的会话变量的模型。我知道纯 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模型的属性发生变化时,它应该为发生变化的属性调用display,然后将Session var设置为模型。但是,如果我的 DateModel 或 PriceModel 发生更改,它似乎不会触发 Special 模型上的更改事件。每个“DateModel”和“PriceModel”都应该有自己的this.on('change', ...)调用Special.set(attribute, thisModel)方法的方法吗?还是有其他方法可以解决这个问题?

4

1 回答 1

2

我看到了几个问题。

首先,你的defaults

defaults: {
    "Product" : null,
    "ShortDescription" : null,
    "Category" : "food",
    "Price" : new PriceModel,
    "Date" : new DateModel,
    "Uses" : 0,
    "Tags" : [],
    "Contributor" : null
}

这将最终得到一个PriceModel、一个DateModel和一个标签数组,该数组被该模型的所有实例共享。一个defaults对象被浅拷贝并合并到模型的属性中,其中没有任何值defaults被克隆或复制,它们只是按原样复制。如果您想要区分PriceDateTags值,请使用函数defaults

defaults: function() {
    return {
        "Product" : null,
        "ShortDescription" : null,
        "Category" : "food",
        "Price" : new PriceModel,
        "Date" : new DateModel,
        "Uses" : 0,
        "Tags" : [],
        "Contributor" : null
    };
}

第二个问题是对变化意味着set什么的看法相当简单。如果您查看 的源代码,您会看到: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不会识别出您的 or 内部发生了某些变化,或者PriceDate从 中添加或删除了某些内容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)为更改,因为这只不过是一种花哨的说法p = p

您可以通过不提供来自的数组来解决此更改问题的一部分;制作副本,更改副本,然后将更新的副本交给. 可以通过绑定到包含和模型上的事件并转发它们来处理一半,类似于集合的处理方式,如下所示:setTagsgetset"change"PriceDate

initialize: function() {
    this.attributes.Price.on(
        'all',
        function(ev, model, opts) { this.trigger(ev, model, opts) },
        this
    );
    //...
}

set如果有人做了 aset('Price', some_new_object)并且您需要重新绑定您的转发器,您可能希望提供自己的实现。

于 2012-11-13T22:05:55.920 回答