How can I persist custom attributes over a collect

2019-06-26 13:07发布

问题:

I have a an "Asset" backbone model that has a custom attribute called "selected". Its custom in the sense that it is not part of the object on the server side. I use to represent which of the list of assets the user has currently selected.

var Asset = Backbone.Model.extend({
    defaults: {
        selected: false
    },

    idAttribute: "AssetId"
});

This model is part of a backbone collection that I fetch periodically to get any changes from the server.

The problem I have is that every time I fetch the collection, the collection is doing a reset (I can tell by the listening for the reset event) and hence the value of the selected attribute is wiped out by the data coming in from the ajax request.

The backbone.js documentation seems to suggest that there is a intelligent merge that will solve this problem. I believe I'm doing this in my fetch methods

 allAssets.fetch({  update: true ,cache: false});

And I have also set the "idAttribute" field in the model so that the ids of the object coming in can be compared with the objects in the collection.

The way I have solved this is by writing my own Parse method in my collection object

 parse: function (response) {
    // ensure that the value of the "selected" for any of the models
    // is persisted into the model in the new collection
    this.each(function(ass) {
        if (ass.get("selected")) {
            var newSelectedAsset = _.find(response, function(num) { return num.AssetId == ass.get("AssetId"); });
            newSelectedAsset.selected = true;
        }
    });
    return response;
}

Is there a better way to do this?

回答1:

Collection.update (introduced in Backbone 0.9.9) does indeed try to merge existing models, but does so by merging all set attributes in the new model into the old model. If you check Backbone source code, you'll see

if (existing || this._byCid[model.cid]) {
    if (options && options.merge && existing) {
        existing.set(model.attributes, options);
        needsSort = sort;
    }
    models.splice(i, 1);
    continue;
}

All attributes, including defaults, are set, that's why your selected attribute is reset to false. Removing the default value for selected will work as intended: compare http://jsfiddle.net/nikoshr/s5ZXN/ to http://jsfiddle.net/nikoshr/s5ZXN/3/

That said, I wouldn't rely on a model property to store my app state, I would rather move it to a controller somewhere else.



标签: backbone.js