I have a scope issue that I don't understand.
I have this object with some methods:
FileInfo = (file) ->
@name = path.basename(file.path);
FileInfo::uploadImage = (filename, callback) ->
FileInfo::handleImage = (version, callback) ->
# Here I would like to call uploadImage
I am calling handleImage from an async.forEach loop as:
async.forEach options, fileInfo.handleImage, (err) -
I would like to call uploadImage from within handleImage but I get TypeError: Object # has no method 'uploadImage'
I have tried, inside of handleImage, the following:
this.uploadImage
as well as:
that = this
that.uploadImage
Neither work.
If I call fileInfo.handleImage outside of the forEach loop it works fine with either this or that.
Change fileInfo.handleImage
to fileInfo.handleImage.bind(fileInfo)
(assuming fileInfo
is an instance of FileInfo
).
It is losing the this
binding (that is, the value of this
when that function is executing, not to be confused with the execution context, see comments) that you expect, because you don't immediately invoke it, just pass a reference to it.
You can either use bind as suggested above or the fat arrow (=>)
However for the fat arrow to work you need to use idiomatic Coffeescript classes. Building a class the normal Javascript way by assigning prototype slots wont work.
class FileInfo
constructor: (file) ->
@name = path.basename(file.path);
uploadImage: (filename, callback) ->
---- fat arrow here
V
handleImage: (version, callback) =>
# Here I would like to call uploadImage
Using it that way will force the CoffeeScript compiler to generate the binding in Javascript for you.