23

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?

1
  • 2
    You should really accept Flambino's answer. It's great!CommentedApr 9, 2014 at 12:37

1 Answer 1

56

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.

5
  • Awesome. Thanks so much for the great answer. Looking forward to trying it out this evening.
    – Brad
    CommentedFeb 13, 2012 at 15:21
  • Goodness, what a fantastic answer :)CommentedJan 16, 2014 at 11:47
  • Shortcut to window.myName: just write @myNameCommentedDec 31, 2014 at 15:30
  • This is a great answer. Good resource for reading more on this?
    – Jeff
    CommentedMay 15, 2015 at 20:29
  • 1
    @Jeff Sorry to say that I can't point to any single resource; namespacing code and avoiding global scope pollution with IIFEs are basic JavaScript best practices, and can be found all over the place. CoffeeScript just follows that when compiling. The rest is just JavaScript and CoffeeScript syntax and semantics, and standard browser runtime behavior (e.g. window being the global object). So it's all aspects of "general client-side development", but each is a topic own its own. But a book on client-side CoffeeScript (or Rails, since that's where it's often used) would probably have something.
    – Flambino
    CommentedMay 24, 2015 at 15:06

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.