如何序列化嵌套的Backbone的集合和模型?
在我的项目中,我使用Backbone集合来安排应用程序的数据,并且还需要将我的数据同步到localstorage。我的数据是一个两层深的嵌套集合和模型,并且存在问题发生的地方。如何序列化嵌套的Backbone的集合和模型?
内部集合与localstorage同步后,它将成为对象的原始数组。所以收集方法(如add
)不能使用。
调试和google搜索后,我找到了原因:
当localStorage的序列化的模型,它调用model.toJSON()
,它只是克隆的模型的属性,不包括嵌套的集合。
// Return a copy of the model's `attributes` object.
toJSON: function(options) {
return _.clone(this.attributes);
},
所以它使用Underscore's clone function,而医生说,它:
创建提供普通对象的浅拷贝克隆。任何嵌套的 对象或数组将被引用复制,而不是重复。
因此,我正在寻找一种深层复制方法来覆盖默认模型的.toJSON
。但我无法弄清楚正确的方法。
例如,我试过如下:
Backbone.Model.prototype.toJSON = function() {
var json = $.extend(true, {}, this.attributes);
return json;
};
编辑的基础上,埃米尔的建议下,我的真实模型去如下:
app.RecordItem = Backbone.Model.extend({
defaults: {
target: 1,
date: '',
day: '',
//foodlist: new TrackList(),
currentvalue: 0,
isSetup: false,
},
initialize: function() {
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var d = new Date();
this.set("date", d.getDate() + "." + months[d.getMonth()]);
this.set("day", days[d.getDay()]);
//
var foodlist = this.getFoodlist();
if (!(foodlist instanceof TrackList)) {
this.set('foodlist', new TrackList(foodlist));
}
},
getFoodlist: function() {
if (!this.foodlist) this.foodlist = new TrackList(this.get('foodlist'));
return this.get('foodlist');
},
toJSON: function(options) {
// this gets the default behavior
var attrs = this.constructor.__super__.toJSON.apply(this, arguments);
var foodlist = attrs.foodlist;
if (foodlist) {
// then replace the collection reference with the actual serialized data
attrs.foodlist = foodlist.toJSON(options);
}
return attrs;
},
});
覆盖后toJSON
方法。该错误消息是
"foodlist.toJSON is not a function(…)"
虽然jQuery's extend
提供深拷贝,这不是你所需要的,这里的原因:
的localStorage存储字符串,所以它需要序列化到JSON。功能将不会被序列化,因为它们在JSON中无效。
因此,这不是一个好主意,试图序列整个骨干集合或模型,而是,序列只有数据和反序列化数据
何时实例嵌套结构回这可以用于持久性,序列化或在发送到服务器之前用于增强 。这个方法的名称有点混乱,因为它实际上并没有返回一个JSON字符串 - 但我很害怕这是JavaScript API for
JSON.stringify
工作的方式。
默认toJSON
行为是为模型的属性做一个浅表副本。由于您要嵌套模型和集合,因此需要更改序列化以考虑嵌套。
完成此操作的一种简单方法是重写toJSON
以调用attributes
哈希中每个嵌套集合和模型的toJSON
函数。
var Daymodel = Backbone.Model.extend({
defaults: { day: 1, },
initialize: function(attrs, options) {
var agenda = this.getAgenda();
if (!(agenda instanceof Todocollection)) {
// you probably don't want a 'change' event here, so silent it is.
return this.set('agenda', new Todocollection(agenda), { silent: true });
}
},
/**
* Parse can overwrite attributes, so you must ensure it's a collection
* here as well.
*/
parse: function(response) {
if (_.has(response, 'agenda')) {
response.agenda = new Todocollection(response.agenda);
}
return response;
},
toJSON: function(options) {
var attrs = Daymodel.__super__.toJSON.apply(this, arguments),
agenda = attrs.agenda;
if (agenda) {
attrs.agenda = agenda.toJSON(options);
}
return attrs;
},
getAgenda: function() {
return this.get('agenda');
},
setAgenda: function(models, options) {
return this.getAgenda().set(models, options);
},
});
其他信息:
- How to handle nested collections and models
- Backbone.localStorage,但没有维护一个良好的开端。
- Modified Backbone
sync
function which handles localStorage
虽然不是不可能的序列化到一个字符串的函数,并与eval
反序列化它,这不是一个好主意,完全没有必要在这里。
嗨Emile,感谢所有这些信息在我的两个发布的问题。但我仍然无法给出正确的行为。请看我更新的编辑。 –
@baoqger你把2个解决方案混合成一个,而它应该工作,你只需要使用一个。我更新了[我的其他答案](http://*.com/a/40823148/1218980)来演示如何重写'parse'并确保该属性始终是一个集合。 –