0

I am developing an application and I am following this rails cast:
http://railscasts.com/episodes/323-backbone-on-rails-part-1

Everything seems correct except that I keep receiving an error when I run my js console at localhost:3000 I get the following:

   Uncaught TypeError: Cannot call method 'on' of undefined     posts_index.js:16
   Voice.Views.PostsIndex.PostsIndex.initialize                 posts_index.js:16
   Backbone.View                                                backbone.js:1147
   PostsIndex                                                   posts_index.js:10 
   Voice.Routers.Posts.Posts.index                              posts_router.js:24
   (anonymous function)                                         backbone.js:900
   (anonymous function)                                         backbone.js:1081
   _.some._.any                                                 underscore.js:209
   _.extend.loadUrl                                             backbone.js:1079
   _.extend.start                                               backbone.js:1046
   window.Voice.initialize                                      voice.js:10
   (anonymous function)                                         voice.js:15
   fire                                                         jquery.js:975
   self.fireWith                                                jquery.js:1083
  jQuery.extend.ready                                           jquery.js:407
  DOMContentLoaded                                              jquery.js:84

Here is my backbone Code for the collections, models, views, routers and templates:

app/assets/javascripts/voice.js.coffee

Window.Voice =
    Models: {}
    Collections: {}
    Views: {}
    Routers: {}
    initialize: ->
            new Voice.Routers.Posts()
            Backbone.history.start()
$(document).ready ->
    Voice.initialize()

app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require underscore
//= require backbone
//= require voice
//= require_tree ../templates
//= require_tree ./models
//= require_tree ./collections
//= require_tree ./views
//= require_tree ./routers
//= require_tree .

javascripts/routers/posts_router.js.coffee

class Voice.Routers.Posts extends Backbone.Router
    routes:
            '': 'index'
    initialize: ->
            @collection = new Voice.Collections.Posts()
            @collection.fetch()
    index: ->
            view = new Voice.Views.PostsIndex()
            $('#container').html(view.render().el)

javascripts/views/posts/posts_index.js.coffee

class Voice.Views.PostsIndex extends Backbone.View

    template: JST['posts/index']

    initialize: ->
            @collection.on('reset', @render, this)

    render: ->
            $(@el).html(@template(posts: @collection))
            this

app/assets/templates/posts/index.jst.eco

<h1> BACKBONE WORKS</h1>
<tr><td>
<%= @posts %>
</td></tr>

javascripts/collections/posts.js.coffee

class Voice.Collections.Posts extends Backbone.Collection
    url: '/api/posts'
    model: Voice.Models.Post

javascripts/models/post.js.coffee

class Voice.Models.Post extends Backbone.Model

config/routes.rb

Voice::Application.routes.draw do
    match '/login' => 'session#create'
    get 'logout', to: 'session#destroy', as: 'logout'
    resources :users
    scope "api" do
            resources :posts
    end
root :to => "main#index"
end

controllers/posts_controller.rb

class PostsController < ApplicationController
  def index
    render :json => Post.all
  end

  def show
    render :json => Post.find(params[:id])
  end

  def upvote
    @post = Post.find(params[:id])
    current_user.like(@post)
    render :json => @post
  end

  def downvote
    @post = Post.find(params[:id])
    current_user.dislike(@post)
    render :json => @post
  end

  def create
    @post = Post.create!(:content => params[:content])
    render :json => @post
  end
end

app/views/main/index.html.erb

<table class = 'table table-bordered table-condensed table-hover'>
        <div id='container'>
        </div>
</table>

Backbone is hard to debug and I have already put in 12 hours + into it. Can somebody help me out?

godzilla3000
  • 246
  • 3
  • 23

1 Answers1

0

Your PostsIndex does this:

initialize: ->
    @collection.on('reset', @render, this)

but you're instantiating it like this:

class Voice.Routers.Posts extends Backbone.Router
    #...
    index: ->
        view = new Voice.Views.PostsIndex()

I think you want to pass the router's @collection to the PostsIndex:

view = new Voice.Views.PostsIndex(collection: @collection)

Backbone will automatically convert that collection option to @collection inside PostsIndex:

constructor / initialize new View([options])

[...] There are several special options that, if passed, will be attached directly to the view: model, collection, el, id, className, tagName and attributes.

so just including collection: @collection when constructing the PostsIndex is sufficient.

mu is too short
  • 426,620
  • 70
  • 833
  • 800