Search code examples
javascriptbackbone.jsweb-applications

Backbone web app architecture - best practice


I am rewriting a web app in backboneJS and I'm wondering about the general architecture compared to my previous approach.

Please let me know if you think this questions should be on CodeReview instead of StackOverflow.

This is how I tried to build web apps MVC style without any framework like backbone or angular:

var App = function() {
    // ...
};

Every main object like App, Page, Product or whatever had it's own model property that holds data typically recieved from a RESTful API interface and a view property that holds a jQuery object with all HTML and event-handlers. It is cloned into the DOM once it's needed.

var Page = function(model) {
    this.model = model;
    this.view = this.render();
}

Page.prototype.render = function() {
    //get template, render it return jQuery object

    return $(html)
}


window.Shop = {
    app: new App({}),
    pages: {
        home: new Page({}),
        products: new Page({})
    }

}

This was my traditional approach to a lot of web apps. It was nicely structured and I always knew where to find my data and my views. More importantly they where part of the same object so I could easily handle my promises and/or deferred objects (hbs templates, API data, etc) between view and model data.

But with Backbone it seems like the View and the Model are their own, separate Objects and I'm not sure if I should handle the View as a child-object of the Model, the other way around or even on the same level.

This is one approach

var PageView = Backbone.View.extend({});
var Page = Backbone.Model.extend({

    initialize: function() {
        this.view = new PageView();
    }

});

window.Shop = {
    pages: {
        home: new Page({}),
        products: new Page({})
    }

}

This is another approach where I see problems because I can't access the view from the model or the other way around (there is no relation between them).

var PageView = Backbone.View.extend({});
var Page = Backbone.Model.extend({});

window.Shop = {
    pages: {
        home: {
            view: new PageView({}),
            model: new Page({})
        },
        products: {
            view: new PageView({}),
            model: new Page({})
        }
    }

}

There are many other possibilities and I'm unsure what's the best way to move forward.


Solution

  • One of the main principles of MVC is that models should never know about the controller/view layer. You should never access a view from a model. This is so that you can use the same model in multiple views.

    In Backbone, you usually pass models into a view when they are created. Check out this following example.

    var User = Backbone.Model.extend({});
    var UserView = Backbone.View.extend({
      render: function() {
        this.$el.html(this.template(this.model.toJSON());
        return this;
      }
    }
    
    var view = new UserView({model: new User()});
    view.render();
    

    Often this is done by fetching a collection from the server and then displaying each model in the collection.

    var User = Backbone.Model.extend({});
    var UserCollection = Backbone.Collection.extend({
      model: User
    });
    
    var UserView = Backbone.View.extend({
      render: function() {
        this.$el.html(this.template(this.model.toJSON());
        return this;
      }
    }
    
    var UsersView = Backbone.View.extend({
      initialize: function() {
        this.listenTo(this.collection, 'reset sync', this.render);
      },
    
      render: function() {
        this.$el.empty();
        this.collection.each(function(user) {
          var view = new UserView({model: user});
          this.$el.append(view.render().el);
        }
        return this;
      }
    }
    
    var users = new UserCollection();
    var view = new UsersView({collection: users});
    users.fetch();
    

    There are many tutorials out there that go more detail, you should check them out.