I'm having trouble accessing and updating what I think is an instance property in coffeescript. I'm trying to update the #cart_total. The first time I update the total, it works fine. However, it only works the first time. It seems the #cart_total is only updating once.
Here's the code:
class Cart
constructor: ()->
#cart_total = 0.00
updateTotal: (amt)->
#cart_total = #cart_total + amt
this.updateTotal( #lineItem.total )
When I call updateTotal, it only seems to work the first time. I am truly grateful for any help - thank you!
EDIT :
I call updateTotal from within the class. I added the code above.
Since you're defining a class, any function calls should be within a method. Unless you're trying to create class methods or variables, but I don't believe that's what you're trying to accomplish here.
This might help:
class Cart
constructor: -> #cart_total = 0
updateTotal: (amt) -> #cart_total += amt
getTotal: -> #cart_total
addTen: -> #updateTotal 10
cart = new Cart
cart.updateTotal 9.50
console.log cart.getTotal()
cart.updateTotal 19.50
console.log cart.getTotal()
cart.addTen()
console.log cart.getTotal()
Note: The spacing is superfluous, but I liked how it looked. Good luck.
Related
I'm trying to define a helper method in konacha in coffeescript, something like this
#expect_int_is_universal = (i) ->
expect(i).to.equal 42
describe '#test', ->
it 'checks if integer is 42', ->
#expect_int_is_universal(42)
Is it possible in konacha?
edit: error log here:
update: the fix is putting it inside a beforeEach block
beforeEach ->
#expect_int_is_universal = (i) ->
expect(i).to.equal 42
describe '#test', ->
it 'checks if integer is 42', ->
#expect_int_is_universal(42)
mu is too short hasn't successfully converted his comment as the answer, but i'll provide it here below:
# (AKA this) inside your it callback is not the same # as at the top level so you're defining expect_int_is_universal as a method on one object but trying to call it as a method on another object. Try without the #s. I don't know enough Konocha, Mocha, or Chai to say any more than that
I've spent days trying to figure out why the template is not updating. Please help! Below is the relevant code.
#Listings = new Meteor.Collection 'listings'
class Map
constructor : (map_canvas=null, map_options=null) ->
#listings = Listings.find()
#observer = new Deps.Dependency()
viewable_listings : ->
#observer.depend()
#listings
set_listings : (listings) ->
#listings = listings
#observer.changed()
So viewable_listings() is set as a template helper
Template.listings.helpers
listings : map.viewable_listings()
But when changing the value of #listings, the template does not update. For example
map.set_listings Listings.find({}, {limit:3})
Does absolutely nothing. No reactive from the listings template. However changing values in the db via Listings.remove(...) works as usual.
The listings helper isn't a function so dependency tracking won't work. The helper will always be the result of the first call to map.viewable_listings(). That value happens to be a cursor so it makes sense that something would render, but would not update when you want it to. Give this a try:
Template.listings.helpers
listings: ->
map.viewable_listings()
I want to join (use) classe in Coffescript files, and i found some usefull ideas here (sry for not including all links), since none fitted my needs (at least not as i like) I tried to find an own solution, this will work fine, but is there something I have overseen?
following "base" and "base class" are not OO words, I just did not find better names
I have a base (class) file TechDraw
class TechDraw
constructor: ->
$(window).load () =>
... do somthing
wave_to_me: ->
say 'I wave' # say is a basic func, I always use for debugging (console.log)
#TechDraw = new TechDraw
this works fine
Now I want to expand/extend my class with "sub classes/modules" in other files; ie. I have a TechDrawLine, and a TechDrawCalc, ans so on
What I did, was building a coffee file for each of them like:
class TechDrawConnector
constructor: (p)->
#parent=p
wave: (msg) ->
say 'yes its me, the connector:',msg
`window.TechDrawConnector = function(p) { return new TechDrawConnector(p) };`
# the last instead of a simple new like
# #TechDrawConnector = new TechDrawConnector
and my base(ic) class/module I extendet like this:
class TechDraw
constructor: ->
$(window).load () =>
#Connector=window.TechDrawConnector(this)
#LineGuy=window.TechDrawLineGuy(this)
#Connector.wave('init')
Since I am a newbee in coffeescript (yes javascript also) my solution feels to simple ...
Have I overseen somthing? The Polution of the global namespace is not so bad I think
You cant create an "extension" that way.
If you define the same class in the same namespace a second time the first class will simply be overwritten and become in accessible. This will mostly be dependent on the order of loading of the compiled JavaScript files.
However you could either later add an method to the prototype of the class
#file a.coffee
class A
constructor: ->
#foo()
#file B.coffee
A::foo = -> #do something
However this is no good style and can certainly be very confusing some time and lead to brittle errors.
Better would be to use a form of dependency injection
#file a.coffee
class A
constructor: (#closure) ->
$(window).load () => #closure()
#file B.coffee
new A () ->
#Connector=window.TechDrawConnector(#)
#LineGuy=window.TechDrawLineGuy(#)
#Connector.wave('init')
I started writing coffeescript last week, as I am programming a new Play20 site where coffeescript is the standard. I want to update a getData function in my class every 5 minutes, but the setInterval function does not bind to my class. Only the first time it calls getData, because the 'this' object is still reachable, as the setUpdateInterval() function is called from within the constructor.
But after the first call, the setInterval does not have any connection anymore with the Widget instance, and does not know what the this.getData() function is (and how to reach it).
Does someone know how to do it?
Here is my code:
class Widget
constructor: (#name) ->
this.setUpdateInterval()
getData: ->
console.log "get Data by Ajax"
setUpdateInterval: (widget) ->
setInterval( this.getData(), 3000000 )
Now here some Javascript magic is required. Reference
class Widget
constructor: (#name) ->
this.setUpdateInterval()
getData: ->
console.log "get Data by Ajax"
setUpdateInterval: (widget) ->
callback = #getData.bind(this)
setInterval( callback, 3000000 )
This will work in almost all browsers (guess which one not), so the
function will have to be bound differently. Some coffeescript magic:
callback = => #getData
The problem is that you are executing the function, instead of passing a reference to it.
Now, it sounds like you need to also keep the scope of the instance. do and => can help with that.
setUpdateInterval: (widget) ->
setInterval (do =>
#getData), 3000000
true
compiles to
Widget.prototype.setUpdateInterval = function(widget) {
var _this = this;
setInterval((function() {
return _this.getData;
})(), 3000000);
return true;
};
you will note the code executes a self invoking function, which return a function, that creates a closure around this, locking it into the scope of the callback (as _this)
Also note that you don't need to pass widget to the method (you aren't using it anywhere), and you would invoke this function in your constructor, to set up the interval. Whatever you do, you only want to call this method once. You could just put the contents of the function in your constructor.
Finally, since coffeescript returns the value of the last statement from all functions, I throw a true in there, but that might no be necessary.
This is handy in node as well. It's a varient of Tass's answer.
class Widget
constructor: (#options = {}) ->
#options.interval ?= 1000
#setInterval()
timer: ->
console.log 'do something'
setInterval: ->
cb = #timer.bind #
setInterval cb, #options.interval
w = new Widget()
I come from a C#/Java background which use a class based OO system and I don't get the JavaScript/CoffeeScript prototype OO system yet. I've written a CoffeeScript class below which allows me to display names for contacts according to a system-side preference. I can only get the class to work by making the joinNonEmpty(stringList, joinText) method belong to the prototype and calling it the way I would call a static method in Java/C# land.
Is there a way I can make this method call using this.joinNonEmpty(...)?
Can you shed some light on why I can reference the firstLastRender, lastFirstRender and firstOrNickThenLast methods in the constructor with this. but it doesn't work from those methods when calling the joinNonEmpty helper?
Does this have something to do with how I'm locating the appropriate method via the preference map?
prefs = displayNameFormat: "FirstOrNickThenLast"
class DisplayNameRenderer
constructor: ->
#prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
# Why does this method have to be static (a class method)?
#joinNonEmpty: (stringList, joinText) ->
nonEmptyStrings = []
for s in stringList
nonEmptyStrings.push(s) if s isnt null and s isnt ""
nonEmptyStrings.join(joinText)
firstLastRender: (contact) ->
# TypeError: Object expected.
joinNonEmpty([contact.firstName, contact.lastName], ' ')
lastFirstRender: (contact) ->
# TypeError: Object doesn't support this method or property
this.joinNonEmpty([contact.lastName, contact.firstName], ', ')
firstOrNickThenLast: (contact) ->
# Works correctly.
DisplayNameRenderer.joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
#prefToRenderMap[prefs.displayNameFormat](contact)
contact = firstName: "Jonathan", nickname: "Jonny", lastName: "Appleseed"
dnr = new DisplayNameRenderer()
# => "Jonny Appleseed"
console.log dnr.render(contact)
Thanks for taking the time to answer.
this (AKA #) is determined when the function is called (with exceptions as below). So when you do this:
#prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
You're storing unbound references to the three functions in the #prefToRenderMap instance variable and #prefToRenderMap is itself an object. Then you try to call the methods in your DisplayNameRenderer instance like this:
#prefToRenderMap[prefs.displayNameFormat](contact)
and everything falls apart because the methods are called in the wrong context and # isn't what they're expecting it to be. If prefs is 'FirstOrNickThenLast' then you're effectively doing this:
#prefToRenderMap.FirstOrNickThenLast(contact)
and # (AKA this) will be #prefToRenderMap inside the firstOrNickThenLast method. But, of course, #prefToRenderMap doesn't have any of the methods that you're trying to call so you get various errors.
One solution is to use the fat arrow (=>) to define the methods:
The fat arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot.
So you could have things like this:
joinNonEmpty: (stringList, joinText) ->
#...
firstLastRender: (contact) =>
#joinNonEmpty([contact.firstName, contact.lastName], ' ')
and everything will work out. Here's a stripped down demo that will also show you your this problem:
http://jsfiddle.net/ambiguous/RAPJw/1/
You could also avoid this problem by referring to the methods by their names. Given a method name in a string, m = 'some_method', you can call that method like this o[m]() in both JavaScript and CoffeeScript and the result will be the same as if you said o.some_method(). A better structure would look more like this:
class DisplayNameRenderer
constructor: ->
#prefToRenderMap =
FirstOrNickThenLast: 'firstOrNickThenLast'
joinNonEmpty: (stringList, joinText) ->
#...
firstOrNickThenLast: (contact) ->
#joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
#[#prefToRenderMap['FirstOrNickThenLast']](contact)
Note the change to the structure of #prefToRenderMap and how it is used in render. And a demo of this approach: http://jsfiddle.net/ambiguous/DFYwu/
As an aside, instead of saying ClassName.class_method() inside an instance method, you can use the constructor property instead: #constructor.class_method(). Also, you usually say #method() or #property rather than this.method() and this.property in CoffeeScript.