Uncaught TypeError: this.template is not a function Backbonejs - ruby-on-rails

I am working in Rails with BackboneJS in handlebar templates.
I am getting a weird error here..
this is my header view
class App.Views.Header extends Backbone.View
className: "navbar-inner"
template: HandlebarsTemplates['app/templates/header']
render: ->
#$el.html(#template())
#
main application file is this
#= require_self
#= require_tree ./templates
#= require_tree ./views
#= require_tree ./routers
window.App =
Routers: {}
Views: {}
Collections: {}
Models: {}
initialize: ->
new App.Routers.MainRouter()
Backbone.history.start()
and my main router file is this
class App.Routers.MainRouter extends Backbone.Router
routes:
"": "index"
initialize: ->
#headerView = new App.Views.Header()
index: ->
$("#header").html(#headerView.render().el)
when I hit localhost:3000.. I got this error upfront.
Uncaught TypeError: this.template is not a function..
Am totally stuck in that any help will be appreciated Thanks

template: HandlebarsTemplates['header']
Template path should be only the template itself.
May that is version due to version or assets precompiled

It sounds like the Handlebars template in HandlebarsTemplates['app/templates/header'] either does not exist, has not been compiled, or there may have been an error while compiling it. That's the error you'd get if that value was null or undefined.
You might want to try setting a breakpoint in your browser's javascript debugger in the call to render, then use the debugger to check the value of this.template and see what's going on.

Related

Error on calling react-modal in rails 4 app

I'm having trouble using react-modal in my rails 4 app with a react-rails front end. I have already followed the steps in this SO question How to call react-modal from rails-assets.org in react-rails component and in this GitHub issue https://github.com/reactjs/react-rails/issues/510 but none of them seem to work.
This is the rails-assets gem in my Gemfile
source 'https://rails-assets.org' do
gem 'rails-assets-react-modal'
end
This is my application.js file
//= require react
//= require ./vendor/react-modal-v1.6.4
//= require react_ujs
//= require react-modal
The //= require ./vendor/react-modal-v1.6.4 call is a call to the compiled file for react-modal. I did this in accordance to the instructions provided in the github issue link above.
Finally, this is my component definition
var ModalTest = React.createClass({
getInitialState: function() {
return {
modalIsOpen: false
}
},
openModal: function() {
this.setState({modalIsOpen: true});
},
closeModal: function() {
this.setState({modalIsOpen: false});
},
render: function() {
return (
<div>
<button className="btn btn-primary" onClick={this.openModal}>
Open Modal
</button>
<ReactModal
isOpen={this.state.modalIsOpen}
onRequestClose={this.closeModal}
contentLabel="Modal"
>
<h1>Test Modal</h1>
</ReactModal>
</div>
);
}
});
I am getting the following error on the console:
Uncaught Error: react-modal: You must set an element with Modal.setAppElement(el) to make this accessible
What am I missing?
Thanks in advance, guys.
I found an answer from yachaka who posted in this GitHub issue for react-modal.
The script is loaded before the DOM, resulting in react-modal setting the parent element of the modal to document.body before it exists.
This can be fixed by adding the lifecycle method componentWillMount as follows:
componentWillMount: function() {
ReactModal.setAppElement('body');
}

Jasmine, RequireJS and Rails

I'm starting to make the move over to requireJS for a project I'm building. I'm currently using jasminerice, rails 3.2 and the require-rails gem.
I've tried to implement http://ryantownsend.co.uk/post/31662285280/jasminerice-and-requirejs-rails-fix with little success, the specs don't run at all.
I am starting to think it maybe I might be better to use requirejs on it's own or maybe the jasmine gem?
I'm not sold on either jasminerice or require-rails gems, so does anyone have any advice on the best tools, and any tips on how to get it up and running/good tutorials?
Ok as I didn't get any response I managed to find a slightly hacky way of making it work.
If you create a file in your view folder jasminerice/spec/index.html.erb (or haml) and copy the html from the jasminerice gem. Replace the spec.js call with:
%script{"data-main"=>"/assets/#{#specenv}", src:"/assets/require.js"}
Then write your spec file like require template like so:
require.config {
paths:{
'jquery':'/assets/jquery'
'underscore': '/assets/underscore-min'
'sinon':'sinon-1.6.0'
'jasmine-sinon':'jasmine-sinon'
'my_js':'my_js'
'my_spec':'my_spec'
}
}
require ['sinon', 'jasmine-sinon', 'jquery', 'underscore', 'my_js', 'my_spec'], () ->
jasmine.getEnv().execute()
This will prevent jasminerice triggering the tests
jasmine.rice.autoExecute = false
Set up your tests with a beforeFilter similar to this(taken from http://kilon.org/blog/2012/08/testing-backbone-requirejs-applications-with-jasmine/)
describe "MySpec", ->
beforeEach ->
flag = false
#thing = ""
that = #
require ['myjs'], (Myjs) ->
flag = true
that.thing = new Myjs()
waitsFor ->
flag
it 'It should exsist', ->
expect(#thing).toBeDefined()
Hope that helps anyone with a similar issue and if anyone has a better solution please post! :)
I have the same setup, here's what I did (starting from the blog post mentioned in the original question):
1. Create a helper to load all spec files
In a file lib/jasminerice/spec_helper.rb, put the following code:
require "requirejs-rails"
module Jasminerice
module SpecHelper
include RequirejsHelper
def spec_files
Rails.application.assets.each_logical_path.select { |lp| lp =~ %r{^spec/.*\.js$} }
end
end
end
This will create a helper method spec_files which you can call in the Jasminerice runner view to automatically get all your specs, so you don't need to update the list of specs every time you add a new one.
2. Override default Jasminerice index view
Create a view named app/views/jasminerice/spec/index.html.erb with the following:
<!doctype html>
<head>
<title>Jasmine Spec Runner</title>
<%= stylesheet_link_tag "jasmine", "spec" %>
<%= requirejs_include_tag 'application' %>
<%= javascript_include_tag "jasminerice", "spec", :debug => true %>
<script>
jasmine.rice.autoExecute = false;
require([<%= spec_files.map { |f| "'#{f.sub(/\.js$/,'')}'" }.join(',').html_safe %>],
function() { jasmine.getEnv().execute() },
function(err) {
var failedId = err.requireModules && err.requireModules[0];
requirejs.undef(failedId);
define(failedId, function() { return function() { console.debug(failedId + ': ' + err); null }; });
require([ failedId ], function() {} );
});
</script>
<%= csrf_meta_tags %>
</head>
<body>
</body>
</html>
This will require all the specs before running Jasmine (with jasmine.getEnv().execute()). I have an ugly hack in there to take the array of spec paths and generate an array of module names in quotes to pass to require.
I've also included an error callback in case there's a problem loading a module -- if you don't do this, your specs will hang when a module load fails. That's especially a problem when you're running them on the command line through guard-jasmine, which is what I do.
Unfortunately I haven't found a very good way to handle such errors -- here I write some info to console.debug and then required the failed module, returning an anonymous function in its place. This allows the specs to run but produces unpredictable results (which is better than no results). I've been struggling to find a better way to deal with this situation, suggestions would be much appreciated.
3. Write some specs
My Jasmine specs take the form:
define (require) ->
MyModule = require 'my-module'
# any other dependencies needed to test
describe 'MyModule', ->
it 'exists', ->
expect(MyModule).toBeDefined()
etc. Note that all my testing dependencies (jasmine, sinon, jasmine-sinon, etc.) I load outside of require, in spec.js.coffee:
#=require sinon
#=require jasmine-sinon
#=require_tree ./helpers/
I put any other helper functions I need in the helpers directory.
4. Bonus
One other tip: if you have problems because your browser won't reload modules even when they change, I use a trick of adding a dummy argument with a timestamp so that the browser will always see a new file and correctly load it.
I created this function in ApplicationController which I load in a before filter:
before_filter :set_requirejs_config
def set_requirejs_config
opts = { :urlArgs => "bust=#{Time.now.to_i}" }) if Rails.env == "development"
Requirejs::Rails::Engine.config.requirejs.run_config.merge!(opts)
end
This adds a query param bust=... to the end of each module name if we're in development mode, so that we always reload modules and get the most up-to-date version. Somewhere there's a post on SO explaining how to do this in RequireJS, but to get it to work with requirejs-rails you have to put it into ApplicationController (and not config/requirejs.yml) so that it is loaded every time you load the page.
Hope that might provide some hints to anyone else using this configuration!

Rails dataTables jquery-datatables-column-filter

I'm using a Railscast way to remotely access Rails data using Ajax. It works fine.
Railscast 340
Now, I'm trying to add the jquery-datatables-column-filter plug-in.
Here is my coffeescript:
$("#workorders").dataTable(
sPaginationType: "full_numbers"
bProcessing: true
bServerSide: true
bFilter: false
sAjaxSource: $('#workorders').data('source')
sDom: "T<\"clear\">lfrtip"
).columnFilter()
But, when I even click on NEXT (to get the 2nd page of workorders), I get the following console error:
Uncaught TypeError: Cannot read property 'sServerMethod' of undefined jquery.dataTables.js?body=1:8754
DataTable.defaults.fnServerData jquery.dataTables.js?body=1:8754
oTable.fnSettings.fnServerData jquery.dataTables.columnFilter.js?body=1:330
_fnAjaxUpdate jquery.dataTables.js?body=1:1898
_fnDraw jquery.dataTables.js?body=1:1431
(anonymous function) jquery.dataTables.js?body=1:2876
fnClickHandler jquery.dataTables.js?body=1:11665
(anonymous function) jquery.dataTables.js?body=1:4800
jQuery.event.dispatch jquery.js?body=1:3075
elemData.handle
And searching a column doesn't work either.
Any ideas? Thanks!
UPDATE1
I tried to even simplify with another index listing (without ajax).
This is the coffeescript:
$("#dataTable1").dataTable().columnFilter()
And when I try to search on a column, I get:
Uncaught TypeError: Cannot read property 'oFeatures' of null jquery.dataTables.js?body=1:5586
fnFilter jquery.dataTables.js?body=1:5586
(anonymous function) jquery.dataTables.columnFilter.js?body=1:65
jQuery.event.dispatch jquery.js?body=1:3075
elemData.handle
Did you drop the Column Filter plugin js into your /vender/assets/javascripts dir? And, then reference in your application.js:
//= require jquery.dataTables.columnFilter
Try to change line 316 in jquery.dataTables.columnFilter.js from this:
oTable.fnSettings().fnServerData = function (sSource, aoData, fnCallback) {
to this:
oTable.fnServerData = function (sSource, aoData, fnCallback) {

uncaught exception: Template undefined not found, ReferenceError: Backbone is not defined

I am trying to follow along with this series:
http://www.backbonerails.com/series/engineering_single_page_apps
I am on episode 5, at around the 48 min mark. When I refresh the page in my browser, I get this in the firebug console:
uncaught exception: Template undefined not found
I tried running my code at http://coffescript.org, and I get this error:
ReferenceError: Backbone is not defined
I'm not sure, but I'm guessing the above error is just occurring because the coffescript.org console doesn't know what Backbone is.
Here is the relevant code:
show_controller.js.coffee
#Demo.module "FooterApp.Show", (Show, App, Backbone, Marionette, $, _) ->
Show.Controller =
showFooter: ->
console.log "footer"
footerView = #getFooterView()
App.footerRegion.show footerView
getFooterView: ->
new Show.Footer
With the above code, I notice in the console that "footer" is not appearing as it should. So maybe something is wrong with the controller? Or something within the "showFooter" method.
list_controller.js.coffee
#Demo.module "HeaderApp.List", (List, App, Backbone, Marionette, $, _) ->
List.Controller =
listHeader: ->
console.log "header"
headerView = #getHeaderView()
App.headerRegion.show headerView
getHeaderView: ->
new List.Header
With the above code, I DO NOTICE that "header" is appearing in the console, so it seems everything is alright with the HeaderApp.
show_view.js.coffee
#Demo.module "FooterApp.Show", (Show, App, Backbone, Marionette, $, _) ->
class Show.Footer extends Marionette.ItemView
template: "footer/show/templates/show_footer"
list_view.js.coffee
#Demo.module "HeaderApp.List", (List, App, Backbone, Marionette, $, _) ->
class List.Header extends Marionette.ItemView
template: "header/list/templates/list_header"
header_app.js.coffee
#Demo.module "HeaderApp", (HeaderApp, App, Backbone, Marionette, $, _) ->
#startWithParent = false
API =
listHeader: ->
HeaderApp.List.Controller.listHeader()
HeaderApp.on "start", ->
API.listHeader()
footer_app.js.coffee
#Demo.module "FooterApp", (FooterApp, App, Backbone, Marionette, $, _) ->
#startWithParent = false
API =
showFooter: ->
FooterApp.Show.Controller.showFooter()
FooterApp.on "start", ->
API.showFooter()
renderer.js.coffee
#Demo.module "FooterApp", (FooterApp, App, Backbone, Marionette, $, _) ->
#startWithParent = false
API =
showFooter: ->
FooterApp.Show.Controller.showFooter()
FooterApp.on "start", ->
API.showFooter()
app.js.coffee
console.log #
#Demo = do (Backbone, Marionette) ->
App = new Marionette.Application
App.addRegions
headerRegion: "#header-region"
mainRegion: "#main-region"
footerRegion: "#footer-region"
App.addInitializer ->
App.module("HeaderApp").start()
App.module("FooterApp").start()
App.on "initialize:after", ->
if Backbone.history
Backbone.history.start()
App
application.js
//= require jquery
//= require lib/underscore
//= require lib/backbone
//= require lib/marionette
//= require_tree ./backbone/config
//= require backbone/app
//= require_tree ./backbone/apps
application.css
#import "twitter/bootstrap";
#import "apps/base";
#import "apps/header";
#import "apps/footer";
Here is the directory structure:
app
assets
javascripts
backbone
apps
footer
show
templates
show_footer.jst.eco
show_controller.js.coffee
show_view.js.coffee
footer_app.js.coffee
header
list
templates
list_header.jst.eco
list_controller.js.coffee
list_view.js.coffee
header.app.js.coffee
config
marionette
renderer.js.coffee
app.js.coffee
application.js
stylesheets
application.css
I'm wondering if all my path stuff is declared correctly based on my directory structure.
Thanks for any help, I'll be awaiting a response eagerly.
Check the following:
The template paths are correct
You've properly overridden the he renderer in renderer.js.coffee and it's getting loaded properly in the HTML (i.e. you can see the code when you view the page's source)
If that looks correct, try comparing your code to the source code provided with the screencast.

Rails 3.1 Backbone JST in View will not compile with events

Working with the rails 3.1 asset pipeline and coffeescript.
I've used the rails-backbone gem for some generation to help me along and everything has been working well for me until I tried to put events to my view. As soon as I put anything to the events attribute the JST does not render (it does without it):
Headspace.Views.Shows ||= {}
class Headspace.Views.Shows.IndexView extends Backbone.View
template: JST["backbone/templates/shows/index"]
el: '#show_listing'
initialize: () ->
#collection = #options.collection
this.render()
events:
'click .show_header' : 'show_details'
show_details = ()->
alert('action')
render: ->
$(#el).html(#template({collection:#collection}))
I've also tried an empty events attribute (which doesn't compile unless I put in the empty {}) which does render the JST. I've considered that el is defined as a string instead of a jQuery element (with $()) until the render function. If I do specify:
el: $('#show_listing')
and:
render: ->
el.html(#template({collection:#collection}))
The JST does not compile.
just a mere typo you got there
instead of
show_details = ()->
alert('action')
it is
show_details : ()->
alert('action')
I am guessing you used shift+enter in textmate for the functions snippet? I have done that, too.

Resources