Render a Backbone.js collection

Cimm picture Cimm · Oct 31, 2011 · Viewed 23.6k times · Source

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...

Answer

dira picture dira · Oct 31, 2011

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});
});