Atom package - setInterval not calling the function - coffeescript

I'm currently working on a package for atom which involves drawing a curve on a canvas. For whatever reason the following code logs "mouseDown" without ever logging "hi" when handleClickDown is called. I've tried without window. but still "mouseDown" is all that's logged. The handleClickDown function is called every time the canvas is clicked if that context helps at all. I'm sure I'm just not understanding something about how setInterval / coffescript works since I'm new to both atom and coffescript. Any help is appreciated.
#printhi: ->
console.log "hi"
handleClickDown: (event, element) ->
console.log "mouseDown"
#mouseDownId = window.setInterval(#printhi,100)
Edit: The following code seems to run fine
console.log "mouseDown"
#mouseDownId = setInterval(()=>
console.log "inner"
,75)
however when using a function like this it throws an error that _this.printhi is not a function
#printhi = () ->
console.log "hi"
handleClickDown: (event, element) ->
console.log "mouseDown"
#mouseDownId = setInterval(()=>
#printhi()
,75)

Ok just answering my own question here as I figured it out eventually. Turns out I was a bit confused on how # and => work in coffeescript. You actually need to remove the # from #printhi: -> so it becomes printhi: -> and then only use it when you're calling it like this #printhi().
Code below worked for me, hope someone finds this helpful
printhi: ->
console.log "hi"
handleClickDown: (event, element) ->
console.log "mouseDown"
#mouseDownId = setInterval(()=>
#printhi()
,75)

Related

Q.defer workaround in Bluebird

I am migrating coffeeScript code from Q to Bluebird and it looks like I have been using promises all wrong, since Bluebird's documentation clearly discourages the use of Promise.defer
The simplified version of my client-server with Q is as follows:
Q = require 'q'
handleRequest = (msg) ->
console.log "Server received #{msg} \n"
deferred = Q.defer()
setTimeout () ->
deferred.resolve "bar"
, 2000
deferred.promise
handleRequest "foo"
.then (msg) ->
console.log msg
Basically I have a function with a promise that will be resolved asynchronously after 2 seconds.
When trying the same approach in Bluebird I get a TypeError saying that the Object function Promise(resolver) has no method 'then' (whole error code is at the end of this post)
Promise = require 'bluebird'
handleRequest = (msg) ->
console.log "Server received #{msg} \n"
new Promise (resolve) ->
"bar"
setTimeout () ->
Promise.resolve()
, 2000
Promise
handleRequest "foo"
.then (msg) ->
console.log msg
I don't know where I am messing it up since Bluebird's documentation for creating a new Promise seems to be just that, a function with resolve/reject functions.
I haven't been able to find any similar approach of promises creation without using promisify.
EventEmitters can do the trick but I really need to use promises in the big version.
There are some other bits of code where the same flow is used: a function where a defer is created/returned and it will be resolved/rejected at some stage.
Thank you very much in advance!!! :)
I have been struggling with this the whole morning.
Server received foo
TypeError: Object function Promise(resolver) {
if (typeof resolver !== "function") {
throw new TypeError("the promise constructor requires a resolver function");
}
if (this.constructor !== Promise) {
throw new TypeError("the promise constructor cannot be invoked directly");
}
this._bitField = 0;
this._fulfillmentHandler0 = void 0;
this._rejectionHandler0 = void 0;
this._promise0 = void 0;
this._receiver0 = void 0;
this._settledValue = void 0;
this._boundTo = void 0;
if (resolver !== INTERNAL) this._resolveFromResolver(resolver);
} has no method 'then'
Googling the error led me to this page of Bluebird's documentation.
So I understand that the async part of the code is the resolution of the promise itself, thus rewriting the code like shown below fixes this issue:
Promise = require 'bluebird'
handleRequest = (msg) ->
new Promise (resolve) ->
setTimeout () ->
resolve "bar"
, 2000
handleRequest "foo"
.then (msg) ->
console.log msg

Docpad: using extendTemplateData via mongoose callback

I'm trying to build a simple plugin to get get data from Mongo into an object over which I can iterate when rendering. The full code is in my project, but the essence of it is a failed attempt to emulate the feedr example. I know the mongoose stuff is working as the console log works, but getting the content sent to the docpad object is defeating me
class mongoPlugin extends BasePlugin
name: 'mongo'
# Fetch list of Gigs
getGigsData: (opts) ->
mongoose.connect ('mongodb://localhost/test')
db = mongoose.connection;
db.on 'error', console.error.bind(console, 'connection error:')
db.once 'open', () ->
gigsSchema = mongoose.Schema {
date : String,
location : String
}
Gigs = mongoose.model 'Gigs', gigsSchema
Gigs.find {}, (err, gigs) ->
mongoose.connection.close()
if err then console.error "db error"
else
console.dir gigs
opts["getGigsData"] = gigs
opts.templateData["getGigsData"] = gigs
return gigs
extendTemplateData: (opts) ->
opts.templateData["getGigsData"] = #getGigsData()
Using node-inspector and triggering a regeneration by editing docpad.coffee, I can see that opts has a field templateData, but it is empty, and is very different from docpad.templateData, so I am picking up the wrong object in the plugin. I can see others did a trick of placing a name in { } but I don't know what that does.
After completing the plugin code I see that my database data becomes the argument to a promise, so perhaps that's where it is supposed to be reintegrated with the docpad.config.templateData but that does not seem to happen in practise
So the main issue here is that we have an asynchronous function getGetsData being executed inside a synchronous function, your templating engine. This simply, isn't possible, as the templating engine will go on and do its thing, while the synchronous stuff happens in the background. This is just an issue with just writing node.js/asynchronous code in general.
The fixes for this is pretty easy to do.
opts.templateData["getGigsData"] = #getGigsData() calls getGigsData without passing over the opts, so that when getGigsData tries and uses the opts, it can't, so that would throw an error. The fix for this is to do #getGigsData(opts)
opts.templateData["getGigsData"] = #getGigsData(opts) assigns the return value of #getGigsData(opts) to the template data, however, the result of this is the result of the db.once call, as that is what will be returned in that scope. When you do return gigs, that's actually the return value for the (err, gigs) -> callback on the Gigs.find call, rather than the return value for the getGigsData. It's all about scopes.
As the database stuff is asynchronous, we need to make getGigsData asynchronous. To do this, we change extendTemplateData: (opts) -> to extendTemplateData: (opts,next) -> to make it asynchronous, and change opts.templateData["getGigsData"] = #getGigsData() to simply return #getGigsData(opts,next)
Now that we have the event and call asynchronous. We now need to make the definition of getGigsData support it. So lets change getGigsData: (opts) -> to getGigsData: (opts,next) -> to take in the completion callback (next) that we defined in step 3. And what we will do, is we will call next where we have return gigs, so lets change return gigs to return next()
It should now work. But as a little bit of cleaning, we can make the error handling better by changing if err then console.error "db error" to return next(err) if err. You will need to fix up the indentation as we will need to remove the else block.
Considering all that, and with a bit more cleaning applied, you'll end up with this:
class mongoPlugin extends BasePlugin
name: 'mongo'
config:
hostname: 'mongodb://localhost/test'
# Fetch list of Gigs
getGigsData: (opts={}, next) ->
config = #getConfig()
docpad = #docpad
mongoose.connect(config.hostname)
db = mongoose.connection
db.on 'error', (err) ->
docpad.error(err) # you may want to change this to `return next(err)`
db.once 'open', ->
gigsSchema = mongoose.Schema {
date: String,
location: String
}
Gigs = mongoose.model('Gigs', gigsSchema)
Gigs.find {}, (err, gigs) ->
mongoose.connection.close()
return next(err) if err
return next(null, gigs)
# Chain
#
extendTemplateData: (opts,next) ->
#getGigsData null, (err, gigs) ->
return next(err) if err
opts.templateData.gigs = gigs
# Chain
#

how to handle implicit return in coffeescript when using async.js

i'm trying to get
testFunction: () ->
console.log "testFunction"
async.series(
(->
console.log "first"
),
(->
console.log "second"
)
)
i've also tried to no success
testFunction: () ->
console.log "testFunction"
async.series(
(->
console.log "first"
return undefined
),
(->
console.log "second"
return undefined
)
)
to run, i would expect console output of "testFunction", "first", "second" but I'm getting "testFunction", "second" and it seems like there is a problem with coffeescript's use of implicit returns, (I guess).
Attached is a screen shot of the javascript output compiled from the above coffeescript.
Every function that does work for async needs to take a callback as its only argument.
one = (callback) ->
console.log "one"
callback()
two = (callback) ->
console.log "two"
callback()
testFunction: () ->
console.log "testFunction"
async.series [one, two], (error) ->
console.log "all done", error
You've got a number of problems. The first is that you're not passing the correct arguments to async.series. It expects:
async.series([functions...], callback)
while you're calling
async.series(function, function)
Since the length attribute of the first function is undefined, it assumes its an empty array and skips straight to the "callback" (second function). It sounds like you may want to pass an array of two functions and omit the callback.
The second problem is that functions passed to async.series must call a callback in order for progression to continue. The callback is the first argument to each function:
testFunction: () ->
console.log "testFunction"
async.series([
((next) ->
console.log "first"
next()
),
((next) ->
console.log "second"
next()
)
])
async ignores the return value of most (all?) functions that you pass to it.

How to write this function in coffeescript

I am struggling to re-produce a function like this in coffeescript could someone help me out a little.
// Listen to message from child window
eventer(messageEvent,function(e) {
console.log('parent received message!: ',e.data);
},false);
Your code translates to this equivalent one in CoffeeScript:
# Listen to message from child window
eventer messageEvent, ((e) ->
console.log "parent received message!: ", e.data
), false
You can always use this tool in the future if you need help with the CoffeeScript equivalence of a JavaScript code:
http://js2coffee.org/
# Listen to message from child window
eventer messageEvent, (e) ->
console.log "parent received message!: #{e.data}"
, false
Verified with coffeescript.org's sandbox CoffeeScript compiler.

Backbone events being fired without trigger

So I have a strange issue where my backbone events are getting fired even though they haven't been triggered yet. Essentially I'm making a note editor application. In the note itself, a user can press cmd + b to bold text, or any of the other normals. That then triggers an event which bubbles up to the AppController which should be subscribed to that event and call the correct method.
Here is the view for the note where the trigger is called:
class MeetingNote.View.NoteView extends Backbone.View
adminTemplate: _.template($('#AdminNoteTemplate').html())
normalTemplate: _.template($('#NormalNoteTemplate').html())
className: 'note'
events:
'keydown' : 'handleKeyDownsForStyling'
# all of the normal backbone stuff.... init/render/blah
handleKeyDownsForStyling: (e) ->
if #admin == true
if e.metaKey
switch e.which
when 66 then #trigger "boldSelection"
when 73 then #trigger "italicizeSelection"
when 85 then #trigger "underlineSelection"
Then here is my AppController which binds to the event when the NoteView is instantiated
class MeetingNote.View.AppController extends Backbone.View
template: _.template($('#MeetingNoteAppTemplate').html())
className: 'MeetingNoteApp'
initialize: (options) ->
#admin = options.privilege
#render()
render: ->
#$el.html(#template())
$('#container').append(#$el)
#initializeApp()
initializeApp: ->
#adminTools = new MeetingNote.View.AdminTools if #admin == true
notes = new MeetingNote.Collection.NotesCollection()
notes.fetch {
success: (collection) =>
_.each collection.models, (model) =>
note = new MeetingNote.View.NoteView {model: model, privilege: #admin}
#bindNoteEvents note if #admin == true
}
bindNoteEvents: (note) ->
note.on "boldSelection", #adminTools.boldSelection(), note
note.on "italicizeSelection", #adminTools.italicizeSelection(), note
note.on "underlineSelection", #adminTools.underlineSelection(), note
lastly, here is the #adminTools.boldSelection() function
boldSelection: ->
console.log( "yo" )
for some reason, upon page load, that console.log is being fired even though I never sent the trigger by pressing cmd + b in the note View. Anyone have any idea why a Backbone.Event would fire automatically?
This is a function call:
#adminTools.boldSelection()
#------------------------^^
This is a reference to a function:
#adminTools.boldSelection
You're supposed to hand on a reference to a function so that it can call the function later. Your bindNoteEvents should look more like this:
bindNoteEvents: (note) ->
note.on "boldSelection", #adminTools.boldSelection, note
note.on "italicizeSelection", #adminTools.italicizeSelection, note
note.on "underlineSelection", #adminTools.underlineSelection, note
# No parentheses here --------------------^^^^^^^^^^^^^^^^^^