如何序列化嵌套的Backbone的集合和模型?

时间:2016-11-26 13:41:52

标签: javascript backbone.js nested backbone-collections

在我的项目中,我使用Backbone集合来安排应用程序的数据,我还需要将我的数据同步到localstorage。我的数据是一个两层深度嵌套的集合和模型,并且存在问题发生的地方。

内部集合同步到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,而文档说明了:

  

创建提供的普通对象的浅层复制克隆。任何嵌套   对象或数组将通过引用复制,而不是重复。

所以我正在搜索深层复制方法来覆盖默认模型的.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(…)"

1 个答案:

答案 0 :(得分:1)

虽然jQuery's extend提供了深层复制,但它并不是您所需要的,这就是原因:

localStorage存储字符串,因此需要序列化为JSON。函数不会被序列化,因为它们在JSON 1 中无效。

因此,尝试序列化整个Backbone集合或模型并不是一个好主意,而是在反序列化数据时仅序列化数据并实例化嵌套结构

Backbone's toJSON

  

这可用于持久性,序列化或扩充   在发送到服务器之前。这个方法的名字有点   令人困惑,因为它实际上并没有返回一个JSON字符串 - 但我是   害怕它是JavaScript API for JSON.stringify的方式   的工作原理。

默认的toJSON行为是制作模型属性的浅表副本。由于您要嵌套模型和集合,因此需要更改序列化以将嵌套考虑在内。

实现此目的的一种简单方法是覆盖toJSON以调用toJSON哈希中每个嵌套集合和模型的attributes函数。

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

其他信息:

1 虽然并非不可能将函数序列化为字符串并使用eval对其进行反序列化,但这不是一个好主意,在这里完全没有必要。< / SUP>