backbone.js - collections and views backbone.js - collections and views jquery jquery

backbone.js - collections and views


From my experience, it's the best to keep in your collection view references to each model's view.

This snippet from the project I'm currently working on should help you get the idea better:

var MyElementsViewClass = Backbone.View.extend({    tagName: 'table',    events: {        // only whole collection events (like table sorting)        // each child view has it's own events    },    initialize: function() {        this._MyElementViews = {}; // view chache for further reuse        _(this).bindAll('add');        this.collection.bind('add', this.add);    },    render: function() {        // some collection rendering related stuff        // like appending <table> or <ul> elements        return this;    },    add: function(m) {        var MyElementView = new MyElementViewClass({            model: m        });        // cache the view        this._MyElementViews[m.get('id')] = MyElementView;        // single model rendering        // like appending <tr> or <li> elements        MyElementView.render();     }});

Taking this approach allows you to update views more efficiently (re-rendering one row in the table instead of the whole table).


I think there are two ways to do it.

  • Use a view per item, and manipulate the DOM yourself. This is what the Todos example does. It's a nice way to do things because the event handling for a single model item is clearer. You also can do one template per item. On the downside, you don't have a single template for the collection view as a whole.
  • Use a view for the whole collection. The main advantage here is that you can do more manipulation in your templates. The downside is that you don't have a template per item, so if you've got a heterogeneous collection, you need to switch in the collection view template code -- bletcherous.

For the second strategy, I've done code that works something like this:

var Goose = Backbone.Model.extend({ });var Gaggle = Backbone.Collection.extend({   model: Goose;};var GaggleView = Backbone.View.extend({    el: $('#gaggle'),    template: _.template($('#gaggle-template').html()),    render: function() {        $(this.el).html(this.template(this.model.toJSON()));    }};var g = new Gaggle({id: 69);g.fetch({success: function(g, response) {    gv = new GaggleView({model: g});    gv.render();}});

The template code would look something like this:

  <script type="text/template" id="gaggle-template">  <ul id="gaggle-list">  <% _.each(gaggle, function(goose) { %>     <li><%- goose.name %></li>  <% }); %>  </ul>  </script>

Note that I use the _ functions (useful!) in the template. I also use the "obj" element, which is captured in the template function. It's probably cheating a bit; passing in {gaggle: [...]} might be nicer, and less dependent on the implementation.

I think when it comes down to it the answer is "There are two ways to do it, and neither one is that great."


The idea of backbone is that view rendering is event driven.

Views attach to Model data change events so that when any data in the model changes the view updates itself for you.

What you're meant to do with collections is manipulate a collection of models at the same time.

I would recommend reading the annotated example.