Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - Calling CoffeeScript from JavaScript

I'm using Rails 3.1 with CoffeeScript and have run into a snag. How do I call a function from a .js.erb file that is located in a .js.coffee file?

Say the function in .js.coffee is the following:

myName = -> "Bob"

I would think I could just call it like any regular js function such as:

var theName = myName();

but that doesn't seem to work. Any ideas?

or is it possible to use coffeescript in my .js.erb file to make everything the same?

like image 617
Brad Avatar asked Feb 13 '12 00:02

Brad


1 Answers

The reason you can't call the CoffeeScript function directly, is that CoffeeScript is wrapped in an immediately-invoked function when compiled. This is done to keep your code from polluting the global namespace.

This is generally A Good Idea™, but of course you can get around it when you need to. If you want a function or other variable to be accessible everywhere (i.e. global scope), you can simply say

window.myName = -> "Bob"

That way, the function is added directly to the global scope, and you can call it from anywhere as window.myName() (or simply as myName() unless the function's being shadowed by a local one).

However, to keep the global namespace as clean as possible, it's best to define a namespace for yourself (like jQuery does, by putting everything into the $ object). For instance, in your first CoffeeScript or JavaScript file (i.e. the first file to be loaded), you can do something like this

window.myNamespace = {};

Then, whenever you want something to be available elsewhere, you can add it to that namespace:

window.myNamespace.myName = -> "Bob"

And then you can call it from anywhere, using window.myNamespace.myName() or simply myNamespace.myName().

Alternatively, you can use CoffeeScript's "assign if undefined or null" operator at the top of all your files:

window.myNamespace ?= {} # create myNamespace if it doesn't already exist

Whichever file gets evaluated first will create the missing window.myNamespace object. Subsequent code will just see that it already exists and skip the assignment. Point is, it'll always be available, regardless of evaluation order.

Edit: Made myNamespace lower-camelcase since it's basically a variable; not a constructor/class

Addendum: You can avoid the function wrapper by using the -b/--bare command line switch, but as mentioned the wrapper is a good thing.

like image 130
Flambino Avatar answered Oct 10 '22 07:10

Flambino