I'm using Backbone.js and Ruby on Rails to render a collection of posts, but nothing is rendering on screen.
App file
#= require_self
#= require_tree ./templates
#= require_tree ./models
#= require_tree ./views
#= require_tree ./routers
window.IntroProject =
Models: {}
Collections: {}
Routers: {}
Views: {}
init: ->
window.router = new IntroProject.Routers.HomepageRouter({})
Backbone.history.start()
$ ->
IntroProject.init()
Model and collection
class IntroProject.Models.Post extends Backbone.Model
paramRoot: 'post'
class IntroProject.Collections.PostsCollection extends Backbone.Collection
model: IntroProject.Models.Post
url: '/'
Router
class IntroProject.Routers.HomepageRouter extends Backbone.Router
initialize: (options) ->
@posts = new IntroProject.Collections.PostsCollection()
@posts.fetch()
routes:
'':'index'
index: ->
@view ||= new IntroProject.Views.Posts.IndexView(collection: @posts)
@view.render()
View
IntroProject.Views.Posts ||= {}
class IntroProject.Views.Posts.IndexView extends Backbone.View
el: '#posts'
template: _.template( $('#home-post-template').html() ) if $("#home-post-template").length
render: ->
@$el.append( @template() )
@
# _.each(@collection, (post) =>
# postHtml = $(@template(post))
# @$el.append( postHtml )
# )
# @
Template
<script type="text/template" id="home-post-template">
<div class="row">
<div class="small-12 columns">
<h2 class="blog-post-title"><%= post.title %></h2>
<small>
<p class="blog-post-meta">Published on <%= post.created_at.strftime('%B %d, %Y') %>
<% if (post.user.email) %>
by <strong><%= post.user.email %></strong>
<% end %>
</p>
</small>
<hr>
<div class="blog-post-body">
<p><%= post.body.html_safe %></p>
</div>
</div>
</div>
</script>
I am able to have the render() called when I load the page because I did a console.log('hello'). I even did console.log(@collection) as well. The output:
PostsCollection {models: Array[0], length: 0, _byId: Object, constructor: function, model: function…}
_byId: Object
_idAttr: "id"
length: 2
models: Array[2]
__proto__: ctor
So they the posts are in the collection.
When I do @$el.append( @template() ) it says post is undefined, so I did @$el.append( @template(post: @collection.models). But the post is undefined.
Overall I understand what's happening, but it doesn't work. I'm missing something important. Here's my github repo
Update:
Changes suggested from answer
Router
class IntroProject.Routers.HomepageRouter extends Backbone.Router
initialize: (options) ->
@posts = new IntroProject.Collections.PostsCollection()
@posts.fetch({ reset : true })
routes:
'':'index'
index: ->
@view ||= new IntroProject.Views.Posts.IndexView(collection: @posts)
View
IntroProject.Views.Posts ||= {}
class IntroProject.Views.Posts.IndexView extends Backbone.View
el: '#posts'
template: _.template( $('#home-post-template').html() ) if $("#home-post-template").length
initialize: ->
@listenTo(@collection, 'reset', @render)
render: ->
_.each(@collection, (post) ->
postHtml = @template( post )
@$el.append( postHtml )
, @)
Template, I removed the post from post.title
Right now I'm getting Uncaught ReferenceError: title is not defined via the console.
@posts.fetch()function. Try implementing asuccesscallback in that function. Example fetch with callback: stackoverflow.com/questions/19713613/… - zer02@collection.each(function(post){ ... });, and you need to call.toJSON()on your post:postHtml = @template( post.toJSON() ), see this basic example: jsbin.com/musupufa/2/edit?html,js,output - christian314159