David Paul Albert
David Paul Albert

Reputation: 67

Can't get template to display using backbone.js and underscore

I'm really new to Backbone, and I've looked everywhere to try and figure this out. Fundamentally I get how Models, Views, Collections and Templates work together, but for some reason I just can't get my Collection to render in a template. Using Firebug, I get a "this.model is undefined"

Here's my code:

(function($) {
window.Category = Backbone.Model.extend({});

window.Categories = Backbone.Collection.extend({
    url: "src/api/index.php/categories?accounts_id=1",
    model: Category
});

window.categories = new Categories();
categories.fetch();

window.CategoriesView = Backbone.View.extend({
    initialize:function () {
        _.bindAll(this,"render");
        this.model.bind("reset", this.render);
    },

    template:_.template($('#tpl-category').html()),

    render:function (eventName) {
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    }
});

var testTargetvar = new CategoriesView({ el: $("#collection") });

})(jQuery) ;

This is the data that my REST service generates:

[
  {
    "name": "Web Design",
    "id": 0
  },
  {
    "name": "Web Development",
    "id": 0
  },
  {
    "name": "Waste Management Solutions",
    "id": 0
  }
]

The "fetch" that I'm using does show the fetched data in Firebug.

And lastly, here's my template:

<div id="collection"></div>
<!-- Templates -->
<script type="text/template" id="tpl-category">
<span><%=name%></span>
</script>

I've verified that all the necessary scripts, jquery, backbone, underscore, etc. are being loaded onto the page properly.

Upvotes: 1

Views: 1932

Answers (2)

JMM
JMM

Reputation: 26837

I don't see where you're setting the model property of the view object. Your view constructor also seems to be confused between whether it represents the collection of categories (as suggested by the #collection selector) or a single category (as suggested by the template and use of the model property). Here is a working example that should help guide you to your complete solution:

http://jsfiddle.net/RAF9S/1/

( function ( $ ) {

  var Category = Backbone.Model.extend( {} );

  var Categories = Backbone.Collection.extend( {

    url : "src/api/index.php/categories?accounts_id=1",

    model : Category

  } );


  var categories = new Categories( [

    { name : "One" },

    { name : "Two" },

    { name : "Three" }

  ] );


  var CategoryView = Backbone.View.extend( {

    initialize : function () {

      _.bindAll( this,"render" );

      this.model.bind( "reset", this.render );

    },


    template : _.template( $( '#tpl-category' ).html() ),


    render : function ( eventName ) {

      this.$el.empty().append(

        $( this.template( this.model.toJSON() ) ).html()

      );


      if ( ! this.el.parentNode ) {

        $( "#collection" ).append( this.el );

      }


      return this;

    }
    // render

  } );


  var view, views = {};

  categories.each( function ( category ) {

    view = new CategoryView( {

      tagName : 'span',

      model : category

    } );


    view.render();

    views[ category.id ] = view;

  } );

} )( jQuery );

In this case I've simply manually populated the collection with several models in lieu of your fetch method. As you can see, I instantiate a view for each model and pass the model object as the model property.

In the render method I empty the view element (this.el / this.$el), then render the template and append the content of its root element to this.$el. That's so I get the new content without wiping out the element itself. Then, for the purposes of this example, I test whether the element is already in the document, and if not I append it to #container.

Upvotes: 1

raddrick
raddrick

Reputation: 4463

I always load my templates in my functions...that might help..

initialize: function(){
  _.bindAll(this, 'render');
  this.template = _.template($('#frame-template').html());
  this.collection.bind('reset', this.render);
},
render: function(){
  var $stages,
    collection = this.collection;
  this.template = _.template($('#frame-template').html());

Upvotes: 0

Related Questions