MattoTodd
MattoTodd

Reputation: 15209

Backbone Model.save() kills all bindings to events

I have been using Backbone on a new project and so far have loved it, but I have come to a blocker that I can't seem to get around.

Without trying to explain my whole domain model, I have found that when you save a model, the response comes back from the server and gets parsed again, creating new sub objects and therefore breaking and event bindings I had previously put on the object.

For instance, if I save ContentCollection (its a Backbone.Model not a collection) when it comes back from the server, the response gets parsed and creates a new Collection in this.contentItems, which breaks all the binding I had on this.contentItems. Is there any way to get around this? Tell backbone not to parse the response somehow? Grab the bindings off the original list, and then re-attach them to the new list?

App.ContentCollection = Backbone.Model.extend({
    urlRoot: '/collection',

    initialize: function() {
    },

    parse: function(resp, xhr) {
        this.contentItems = new App.ContentList(resp.items)
        this.subscriptions = new App.SubscriptionList(resp.subscriptions)

        return resp
    },

    remove: function(model){
        this.contentItems.remove(model)
        this.save({'removeContentId':model.attributes.id})
    },

    setPrimaryContent: function(model){
        this.save({'setPrimaryContent':model.attributes.id})
    }
})

Has anyone run into this before?

Upvotes: 2

Views: 263

Answers (1)

nrabinowitz
nrabinowitz

Reputation: 55678

I think the issue here is the way you're using the parse() method. Backbone just expects this method to take a server response and return a hash of attributes - not to change the object in any way. So Backbone calls this.parse() within save(), not expecting there to be any side-effects - but the way you've overridden .parse(), you're changing the model when the function is called.

The way I've dealt with this use case in the past is to initialize the collections when you first call fetch(), something like:

App.ContentCollection = Backbone.Model.extend({

    initialize: function() {
        this.bind('change', initCollections, this);
    },

    initCollections: function() {
        this.contentItems = new App.ContentList(resp.items);
        this.subscriptions = new App.SubscriptionList(resp.subscriptions);
        // now you probably want to unbind it,
        // so it only gets called once
        this.unbind('change', initCollections, this)
    },

    // etc
});

Upvotes: 3

Related Questions