Render a Backbone.js collection

23,825

Solution 1

The problem is that when you define ContinentsView, the template is evaluated and it uses $('#continents-template') - but the DOM is not ready yet, so it does not find the template.

To solve it, simply move the template assignment in the initialize function:

ContinentsView = Backbone.View.extend({
  el: '#continents',
  initialize: function() {
     this.template = _.template($('#continents-template').html());
  }
  ...

Regarding collections, yes, they are grouping objects, specifically sets of models.

You should make the code so the models (and collections) do NOT know about the views, only the views know about models.

ContinentModel = Backbone.Model.extend({});

ContinentsCollection = Backbone.Collection.extend({
  model: ContinentModel,
  // no reference to any view here    
});

ContinentsView = Backbone.View.extend({
  el: '#continents',

  initialize: function() {
    this.template = _.template($('#continents-template').html());
    // in the view, listen for events on the model / collection
    this.collection.bind("reset", this.render, this);
  },

  render: function() {
    var renderedContent = this.template(this.collection.toJSON());
    $(this.el).html(renderedContent);
    return this;
  }
});

$(function() {
  var continentsCollection = new ContinentsCollection();
  continentsCollection.reset([{name: "Asia"}, {name: "Africa"}]);
  // initialize the view and pass the collection
  var continentsView = new ContinentsView({collection: continentsCollection});
});

Solution 2

It is also worth noting there are additional complexities that quickly rear their heads when rendering a collection in a view. For instance, the view generally needs to be re-rendered when models are added or removed from the collection. It isn't rocket science to implement your own solution, but it is probably worth looking into existing solutions since there are quite a few tried and tested ones out there.

Backbone.CollectionView is a robust collection view class that handles selecting models in response to mouse clicks, reordering the collection based on drag and drop, filtering visible models, etc.

Several popular frameworks built on top of backbone also provide simple collection view classes, like Backbone.Marionette, Chaplin, and Layout Manager.

Even though Backbone itself does not provide any structure for rendering a collection, it is a non-trivial problem and lots of people have different opinions on how it should be done. Luckily it is such a common need that there are quite a few good options already in the eco system.

Share:
23,825
Cimm
Author by

Cimm

Intrigued by the web and its potential, convinced it will keep reinventing itself and happy to be part of that. Feels there is not enough time to build all the applications he comes up with.

Updated on May 28, 2020

Comments

  • Cimm
    Cimm almost 4 years

    I am a Backbone.js n00b and trying to get my head around it. I know how to render a model using a view and the built-in underscore.js templating engine. Now I'm trying to render a collection and that's where I get stuck. There is no server here, so I'm not fetching anything remotely, just a simple HTML page with some JavaScript.

    ContinentModel = Backbone.Model.extend({});
    
    ContinentsCollection = Backbone.Collection.extend({
      model: ContinentModel,
    
      initialize: function () {
        this.continentsView = new ContinentsView;
        this.bind("reset", this.continentsView.render);
      }
    });
    
    ContinentsView = Backbone.View.extend({
      el: '#continents',
      template: _.template($('#continents-template').html()),
    
      render: function() {
        var renderedContent = this.template(this.collection.toJSON());
        $(this.el).html(renderedContent);
        return this;
      }
    });
    
    $(function() {
      var continentsCollection = new ContinentsCollection();
      continentsCollection.reset([{name: "Asia"}, {name: "Africa"}]);
    });
    

    It breaks on the template attribute line in the view but I'm not sure that's where I need to look. Am I supposed to render a collection or do I miss the point completely here (maybe collections are just grouping objects and I shouldn't look at it as a list I can render)?

    Thanks for helping...

  • Cimm
    Cimm over 12 years
    Thanks Dira! The template does work now and the tip that models should't know about the views really helps. Still the reset doesn't seem to trigger the view render function. Any ideas?
  • Cimm
    Cimm over 12 years
    Sorry, got it, I have to switch the last 2 lines in your example off course. I have to initialize the continentsView before resetting the collection. Thanks!
  • Brian Genisio
    Brian Genisio over 12 years
    @dira +1 Thank you very much for pointing out that models/collections should not reference the view (directly, at least). My eyes were bleeding for a moment. :)