I'm new to CoffeeScript, and I seem to be having trouble with the syntax for calling methods.
Here's the Card model:
class exports.Card extends Backbone.Model
defaults:
pip: '4'
suit: '♠'
color: 'b'
rows: ->
rows =
'4': [2, 0, 2]
rows[@pip]
And the relevant portion of the template:
<ul class="col cols-<%= @card.rows()[0] %>">
which is giving me the error Uncaught TypeError: Object #<Object> has no method 'rows'
Specifically, I'm wondering if I'm using incorrect syntax for the rows method of Card or if I'm just misunderstanding something. Thanks in advance!
Update:
For some reason, @card.property
always works fine, but @card.any_method()
never does. I've gotten around this at the moment by using properties, but I'd love it if someone was able to explain this behavior. Thanks again!
Update 2:
I'm using if it's a help to anyone, and here's the main.coffee
file to show how the @card
instance is being created and passed to the view.
window.app = {}
app.routers = {}
app.models = {}
app.collections = {}
app.views = {}
Card = require('models/card_model').Card
MainRouter = require('routers/main_router').MainRouter
HomeView = require('views/home_view').HomeView
CardView = require('views/card_view').CardView
# app bootstrapping on document ready
$(document).ready ->
app.initialize = ->
app.routers.main = new MainRouter()
app.views.home = new HomeView()
app.views.card = new CardView(model: new Card(color: 'r', suit: '♥', pip: '7'))
app.routers.main.navigate 'home', true if Backbone.history.getFragment() is ''
app.initialize()
Backbone.history.start()
I'm new to CoffeeScript, and I seem to be having trouble with the syntax for calling methods.
Here's the Card model:
class exports.Card extends Backbone.Model
defaults:
pip: '4'
suit: '♠'
color: 'b'
rows: ->
rows =
'4': [2, 0, 2]
rows[@pip]
And the relevant portion of the template:
<ul class="col cols-<%= @card.rows()[0] %>">
which is giving me the error Uncaught TypeError: Object #<Object> has no method 'rows'
Specifically, I'm wondering if I'm using incorrect syntax for the rows method of Card or if I'm just misunderstanding something. Thanks in advance!
Update:
For some reason, @card.property
always works fine, but @card.any_method()
never does. I've gotten around this at the moment by using properties, but I'd love it if someone was able to explain this behavior. Thanks again!
Update 2:
I'm using http://brunchwithcoffee.com if it's a help to anyone, and here's the main.coffee
file to show how the @card
instance is being created and passed to the view.
window.app = {}
app.routers = {}
app.models = {}
app.collections = {}
app.views = {}
Card = require('models/card_model').Card
MainRouter = require('routers/main_router').MainRouter
HomeView = require('views/home_view').HomeView
CardView = require('views/card_view').CardView
# app bootstrapping on document ready
$(document).ready ->
app.initialize = ->
app.routers.main = new MainRouter()
app.views.home = new HomeView()
app.views.card = new CardView(model: new Card(color: 'r', suit: '♥', pip: '7'))
app.routers.main.navigate 'home', true if Backbone.history.getFragment() is ''
app.initialize()
Backbone.history.start()
Share
Improve this question
edited Aug 26, 2011 at 20:57
mportiz08
asked Aug 26, 2011 at 5:46
mportiz08mportiz08
10.3k12 gold badges41 silver badges42 bronze badges
3
|
3 Answers
Reset to default 14Your method calling syntax is correct. The relevant rules for CoffeeScript are:
Parenthesis are optional for method calls invoked with arguments ie
object.method 1,2
or
object.method(1,2)
Parenthesis are required for method calls invoked with no arguments ie
object.method()
To see how this works try running the following code on the 'Try CoffeeScript' editor on the CoffeeScript site:
class A
method: ->
console.log "A"
(new A()).method();
Since your method call syntax is correct it seems likely that the problem is that the @card variable is not an instance of the exports.Card class.
The problem is that pip
isn't a property of the Card
instance; it's a property of Card::defaults
, so Backbone then makes it an attribute of the Card
instance—not a property. You can access the pip
attribute with
card.get 'pip'
or directly as
card.attributes.pip
The reason for this distinction is that, in JavaScript, there's no way to monitor a property for changes, which Backbone needs to do in order to dispatch events. (If you modify pip
with card.set 'pip'
, then Backbone fires a "change"
event, for instance.)
So, your code should work fine if you just change the last line of the rows
method:
rows: ->
rows =
'4': [2, 0, 2]
rows[@get 'pip']
(Note: Getters/setters are supported in some JS environments, which would allow you to map card.pip = ...
to card.set 'pip', ...
See John Resig's article on it here. Backbone doesn't use this approach because it aims to be compatible with all modern-ish browsers.)
Finally figured it out--I forgot that the @card
variable referenced in the template didn't originate from the main.coffee
file--it was actually being converted into JSON in the CardView
here:
cardTemplate = require('templates/card')
class exports.CardView extends Backbone.View
tagName: 'div'
className: 'card'
render: ->
$(@el).html cardTemplate(card: @model.toJSON())
@
Now it makes sense why only variables were working and not methods -- @card
was actually a JSON representation of the model instance.
Thanks for all the suggestions/clarifications guys--sorry for the dumb mistake :P
@card
created? Asnew exports.Card
? Does it pass the test@card instanceof exports.Card
? – Trevor Burnham Commented Aug 26, 2011 at 19:58{Card} = require 'models/card_model'
instead ofCard = require('models/card_model').Card
. – Trevor Burnham Commented Aug 27, 2011 at 15:59