Tôi đã gặp vấn đề tương tự và tôi đang thử nghiệm với mã trong câu trả lời của rycfung , đó là một gợi ý tuyệt vời.
Tuy nhiên, nếu bạn không muốn set
trực tiếp đến các mô hình lồng nhau hoặc không muốn liên tục chuyển {parse: true}
vào options
, một cách tiếp cận khác sẽ là xác định lạiset
bản thân.
Trong Backbone 1.0.0 , set
được gọi trong constructor
, unset
, clear
, fetch
vàsave
.
Hãy xem xét siêu mô hình sau đây , cho tất cả các mô hình cần lồng mô hình và / hoặc bộ sưu tập.
/** Compound supermodel */
var CompoundModel = Backbone.Model.extend({
/** Override with: key = attribute, value = Model / Collection */
model: {},
/** Override default setter, to create nested models. */
set: function(key, val, options) {
var attrs, prev;
if (key == null) { return this; }
// Handle both `"key", value` and `{key: value}` -style arguments.
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
// Run validation.
if (options) { options.validate = true; }
else { options = { validate: true }; }
// For each `set` attribute, apply the respective nested model.
if (!options.unset) {
for (key in attrs) {
if (key in this.model) {
if (!(attrs[key] instanceof this.model[key])) {
attrs[key] = new this.model[key](attrs[key]);
}
}
}
}
Backbone.Model.prototype.set.call(this, attrs, options);
if (!(attrs = this.changedAttributes())) { return this; }
// Bind new nested models and unbind previous nested models.
for (key in attrs) {
if (key in this.model) {
if (prev = this.previous(key)) {
this._unsetModel(key, prev);
}
if (!options.unset) {
this._setModel(key, attrs[key]);
}
}
}
return this;
},
/** Callback for `set` nested models.
* Receives:
* (String) key: the key on which the model is `set`.
* (Object) model: the `set` nested model.
*/
_setModel: function (key, model) {},
/** Callback for `unset` nested models.
* Receives:
* (String) key: the key on which the model is `unset`.
* (Object) model: the `unset` nested model.
*/
_unsetModel: function (key, model) {}
});
Lưu ý rằng model
, _setModel
và _unsetModel
được để trống có mục đích. Ở mức trừu tượng này, bạn có thể không thể xác định bất kỳ hành động hợp lý nào cho các lệnh gọi lại. Tuy nhiên, bạn có thể muốn ghi đè chúng trong các mô hình con mở rộng CompoundModel
.
Ví dụ, các lệnh gọi lại đó rất hữu ích để ràng buộc người nghe và tuyên truyền change
các sự kiện.
Thí dụ:
var Layout = Backbone.Model.extend({});
var Image = CompoundModel.extend({
defaults: function () {
return {
name: "example",
layout: { x: 0, y: 0 }
};
},
/** We need to override this, to define the nested model. */
model: { layout: Layout },
initialize: function () {
_.bindAll(this, "_propagateChange");
},
/** Callback to propagate "change" events. */
_propagateChange: function () {
this.trigger("change:layout", this, this.get("layout"), null);
this.trigger("change", this, null);
},
/** We override this callback to bind the listener.
* This is called when a Layout is set.
*/
_setModel: function (key, model) {
if (key !== "layout") { return false; }
this.listenTo(model, "change", this._propagateChange);
},
/** We override this callback to unbind the listener.
* This is called when a Layout is unset, or overwritten.
*/
_unsetModel: function (key, model) {
if (key !== "layout") { return false; }
this.stopListening();
}
});
Với điều này, bạn có thể tự động tạo mô hình lồng nhau và truyền sự kiện. Việc sử dụng mẫu cũng được cung cấp và thử nghiệm:
function logStringified (obj) {
console.log(JSON.stringify(obj));
}
// Create an image with the default attributes.
// Note that a Layout model is created too,
// since we have a default value for "layout".
var img = new Image();
logStringified(img);
// Log the image everytime a "change" is fired.
img.on("change", logStringified);
// Creates the nested model with the given attributes.
img.set("layout", { x: 100, y: 100 });
// Writing on the layout propagates "change" to the image.
// This makes the image also fire a "change", because of `_propagateChange`.
img.get("layout").set("x", 50);
// You may also set model instances yourself.
img.set("layout", new Layout({ x: 100, y: 100 }));
Đầu ra:
{"name":"example","layout":{"x":0,"y":0}}
{"name":"example","layout":{"x":100,"y":100}}
{"name":"example","layout":{"x":50,"y":100}}
{"name":"example","layout":{"x":100,"y":100}}