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
    }
});

示されているように、特殊モデルの属性が変更されると、変更された属性のdisplayを呼び出してから、Session変数をモデルに設定する必要があります。ただし、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
}

その結果、そのモデルのすべてのインスタンスで1つPriceModel、1つDateModel、および1つのタグ配列が共有されます。defaultsオブジェクトは浅くコピーされ、モデルの属性にマージされます。の値はdefaults複製または複製されず、そのままコピーされます。、、、および値を区別する場合は、次の関数を使用しPriceます。DateTagsdefaults

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

2番目の問題は、変更の意味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の内部で何かが変更されたこと、またはから何かを追加または削除したことを認識しません。このようなことをする場合:PriceDateTags

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実装を提供しset('Price', some_new_object)、フォワーダーを再バインドする必要があります。

于 2012-11-13T22:05:55.920 に答える