如何序列化嵌套 Backbone 的集合和模型?
How to serialize nested Backbone's collections and models?
在我的项目中,我使用Backbone集合来整理应用程序的数据,我还需要将我的数据同步到本地存储。我的数据是一个两层深度嵌套的集合和模型,这就是问题所在。
内部集合同步到localstorage后,变成原始对象数组。所以采集方式(如add
)无法使用
经过调试和谷歌搜索,我找到了原因:
当 localStorage 序列化模型时,它调用 model.toJSON()
,它只是克隆模型的属性,不包括嵌套集合。
// Return a copy of the model's `attributes` object.
toJSON: function(options) {
return _.clone(this.attributes);
},
所以它使用 Underscore's clone function,文档说它:
Create a shallow-copied clone of the provided plain object. Any nested
objects or arrays will be copied by reference, not duplicated.
所以我正在寻找一种深层复制方法来覆盖默认模型的 .toJSON
。但我想不出正确的方法。
例如,我尝试了以下操作:
Backbone.Model.prototype.toJSON = function() {
var json = $.extend(true, {}, this.attributes);
return json;
};
编辑,根据Emile的建议,我的真实模型如下:
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。函数不会被序列化,因为它们在 JSON1.
中无效
因此,尝试序列化整个 Backbone 集合或模型并不是一个好主意,而是仅序列化数据并在反序列化数据时实例化嵌套结构
This can be used for persistence, serialization, or for augmentation
before being sent to the server. The name of this method is a bit
confusing, as it doesn't actually return a JSON string — but I'm
afraid that it's the way that the JavaScript API for JSON.stringify
works.
默认的 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);
},
});
附加信息:
- Backbone.localStorage,未维护,但一个好的开始。
1 虽然将函数序列化为字符串并使用 eval
反序列化并非不可能,但这不是一个好主意,而且完全没有必要这里。
在我的项目中,我使用Backbone集合来整理应用程序的数据,我还需要将我的数据同步到本地存储。我的数据是一个两层深度嵌套的集合和模型,这就是问题所在。
内部集合同步到localstorage后,变成原始对象数组。所以采集方式(如add
)无法使用
经过调试和谷歌搜索,我找到了原因:
当 localStorage 序列化模型时,它调用 model.toJSON()
,它只是克隆模型的属性,不包括嵌套集合。
// Return a copy of the model's `attributes` object.
toJSON: function(options) {
return _.clone(this.attributes);
},
所以它使用 Underscore's clone function,文档说它:
Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.
所以我正在寻找一种深层复制方法来覆盖默认模型的 .toJSON
。但我想不出正确的方法。
例如,我尝试了以下操作:
Backbone.Model.prototype.toJSON = function() {
var json = $.extend(true, {}, this.attributes);
return json;
};
编辑,根据Emile的建议,我的真实模型如下:
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。函数不会被序列化,因为它们在 JSON1.
中无效因此,尝试序列化整个 Backbone 集合或模型并不是一个好主意,而是仅序列化数据并在反序列化数据时实例化嵌套结构
This can be used for persistence, serialization, or for augmentation before being sent to the server. The name of this method is a bit confusing, as it doesn't actually return a JSON string — but I'm afraid that it's the way that the JavaScript API for
JSON.stringify
works.
默认的 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);
},
});
附加信息:
- Backbone.localStorage,未维护,但一个好的开始。
1 虽然将函数序列化为字符串并使用 eval
反序列化并非不可能,但这不是一个好主意,而且完全没有必要这里。