verdure
verdure

Reputation: 3341

Update a Backbone view when model is saved

I have the following scenario -

window.Wine = Backbone.Model.extend({
  urlRoot: '/wines'

});
window.WineCollection = Backbone.Collection.extend({
   model: Wine,
   url: "/wines"
});

I have a model and the respective collection defined.

window.WineListView = Backbone.View.extend({
    el: '#wineList',
    initialize: function () {
        this.model.bind("reset", this.render, this);
        this.model.bind("add", function (wine) {
            alert("model added");
        });
    },
    render: function (eventName) {
        _.each(this.model.models, function (wine) {
            $(this.el).append(new WineListItemView({
                model: wine
            }).render().el);
        }, this);
        return this;
    }
});
window.WineListItemView = Backbone.View.extend({
    tagName: "li",
    initiliaze: function () {
        this.render();
    },
    render: function (eventName) {
        var template = _.template($('#wine-list-item').html());
        $(this.el).html(template(this.model.toJSON()));
        return this;
    }
});

The above views creates an individual list item for each model.

window.WineView = Backbone.View.extend({
    el: $("#mainArea"),
    initialize: function () {
        this.render();
    },
    render: function (eventName) {
        var template = _.template($("#wine-details").html(), {});
        $(this.el).html(template);
    },
    events: {
        "click #save_form": "save_form"
    },
    save_form: function () {
        var wine = new Wine();
        wine.save();
        return false;
    }
});
window.HeaderView = Backbone.View.extend({
    el: '.header',
    initialize: function () {
        this.render();
    },
    render: function (eventName) {
        var template = _.template($('#header').html());
        $(this.el).html(template());
        return this;
    },
    events: {
        "click .new": "newWine"
    },
    newWine: function (event) {
        var wine_View = new WineView();
        wine_View.render();
    }
});

In WineView, when the submit button of the form is clicked the model is saved. The Backbone.sync function is overridden.

var AppRouter = Backbone.Router.extend({
    routes: {
        "": "list"
    },
    list: function () {
        this.wineList = new WineCollection();
        this.wineListView = new WineListView({
            model: this.wineList
        });
        this.wineList.fetch();
    }
});
var app = new AppRouter();
Backbone.history.start();
var header = new HeaderView();

My concern is, when the model is saved the WineListView doesn't get refreshed and show the new model that has been added. Precisely the this.mode.bind("add") doesn't get invoked.

I apologize for the verbosity of the question. But, this has been bothering me a for almost a week. Any help is greatly appreciated.

Cheers!

Upvotes: 8

Views: 6616

Answers (2)

Sander
Sander

Reputation: 13421

the reason add is never called is exactly that once your wine is saved wine.save(); you should add a success function and add it to the winelist collection

try this:

wine.save(wine.toJSON(), {
    success: function(){ 
        // model was saved successfully, now add it to the collection
        yourwinelist.add(wine);
        // if you can't access your wine list from this context, you might want to raise an event, and pass the wine, to catch it somewhere else:
        obj.trigger('myWineAdded', wine); // this can be raised on a global event aggregator
    },
    error: function(){ 
        // handle app when saving to server fails
        alert('failed to save wine');
    }
});

more info on the event aggregator idea check this :
Routing and the event aggregator coordinating views in backbone.js

Upvotes: 5

polarblau
polarblau

Reputation: 17734

From what I can see, you're never actually adding the new model to the collection. An easy way to do this, would be the collection's create method (assuming you have made the collection available):

save_form: function () {
    this.collection.create({ MODEL ATTRIBUTES HERE … });
    return false;
}

As the documentation states

[t]he create method can accept either an attributes hash or an existing, unsaved model object.

Creating the new model like this, should trigger an add event on the collection if I'm not mistaken.

Another way, which — according to the docs should definitely trigger an add event (again, on the collection, not the model!)

save_form: function () {
    var wine = new Wine();
    this.collection.add(wine);
    return false;
}

Add a model (or an array of models) to the collection. Fires an "add" event, which you can pass {silent: true} to suppress.

In any case, remember to change your event binding:

this.collection.bind("add", function (wine) {
    alert("model added");
});

Upvotes: 1

Related Questions