29

I can't for the life of me figure this out or find a solution online. I am trying to figure out how to write a script in CoffeeScript from jQuery based JavaScript.

The script is this:

jQuery('.post-thumb a').hover( function() {
    jQuery(this).find('.overlay').fadeIn(150);
}, function() {
    jQuery(this).find('.overlay').fadeOut(150);
});

I initially tried rewriting that like this:

thumb_overlay =>
    $('.post-thumb a').hover
        => $(this).find('.overlay').fadeIn(150)
        ,=> $(this).find('.overlay').fadeOut(150)

But that didn't work, so I thought I would post here. So how do I write that JavaScript in CoffeeScript?

Dave Long
  • 9,569
  • 14
  • 59
  • 89

2 Answers2

69

I think you're almost there but you need some parentheses (to group things) and some backslashes to keep CoffeeScript from misinterpreting the newlines. Try this:

thumb_overlay =>
    $('.post-thumb a').hover \
        (=> $(this).find('.overlay').fadeIn(150)), \
        (=> $(this).find('.overlay').fadeOut(150))

You could also mash it all into one line but you might regret it in a few months:

thumb_overlay =>
    $('.post-thumb a').hover (=> $(this).find('.overlay').fadeIn(150)), (=> $(this).find('.overlay').fadeOut(150))

And BTW, go to the homepage and hit "Try CoffeeScript", that's an easy way to sort small bits of CoffeeScript out; start with the -> version to cut down on the noise in the JavaScript and then switch to => when you get the right JavaScript.

I'm not sure if you want to => forms in this case, the -> form form:

$('.post-thumb a').hover \
    (-> $(this).find('.overlay').fadeIn(150)), \
    (-> $(this).find('.overlay').fadeOut(150))

would give you the the JavaScript that you started with:

$('.post-thumb a').hover((function() {
  return $(this).find('.overlay').fadeIn(150);
}), (function() {
  return $(this).find('.overlay').fadeOut(150);
}));

And if you don't like backslashes, you could do this:

$('.post-thumb a').hover( 
    -> $(this).find('.overlay').fadeIn(150)
    -> $(this).find('.overlay').fadeOut(150)
)

Or if your functions are longer, you could give them names and skip a lot of the problem:

fadeIn  = -> $(this).find('.overlay').fadeIn(150)
fadeOut = -> $(this).find('.overlay').fadeOut(150)
$('.post-thumb a').hover(fadeIn, fadeOut)

I tend to prefer this approach in both JavaScript and CoffeeScript, reads better to me.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • 1
    The second backslash is unnecessary. The first is only necessary because you're omitting parentheses and the CoffeeScript parser will assume that the line is a complete function call unless you explicitly include a backslash to indicate the line continues. If you parenthesized, you wouldn't need any backslashes. – Chuck Aug 16 '11 at 04:32
  • @Chuck: We can call that personal preference. I actually like parentheses so I'd use them (and ignore the dirty looks) but a lot of people seem not to like them. I'd probably go with my (updated) last version in Real Life but I don't do that much CoffeeScript so I'm still fumbling around a bit. – mu is too short Aug 16 '11 at 04:41
  • I had been trying to do the Try CoffeeScript to make sure it worked, but nothing would compile beyond the hover method (none of the arguments), so I new I had something wrong. Is there a way to load the interactive console with jQuery to test there? – Dave Long Aug 16 '11 at 15:04
  • @Dave: Not that I know of. You might be able to make something go with jsfiddle and http://jsfiddle.net/kaleb/neEp4/ though. – mu is too short Aug 16 '11 at 18:01
  • I actually found a Coda plugin that lets me compile and test coffeescript with jQuery – Dave Long Aug 16 '11 at 20:31
  • In your last example, the second comma is not needed either. – Sal Rahman May 12 '13 at 05:44
  • @skizeey: True enough, thanks. I've done a bit more CoffeeScript since this answer, these days I'd probably go with this structure just to avoid having to worry about the whitespace: `a = -> ...; b = -> ...; $(x).hover(a, b)` (with better names of course). – mu is too short May 12 '13 at 06:10
  • @mu is too short: sorry, I meant the first comma, but I guess you understood what I meant. Regarding your solution: it would definitely work a lot of the times. But bear in mind, though, that CoffeeScript uses [implicit scoping](http://lucumr.pocoo.org/2011/12/22/implicit-scoping-in-coffeescript/) and so initializing those functions could over-write a variable that you declared of the same name, in an upper scope. But that's just a precaution. – Sal Rahman May 12 '13 at 08:01
  • @skizeey: But if you're having that sort of scoping problem then your code is probably a hopeless incomprehensible mess. – mu is too short May 12 '13 at 08:20
  • I prefer this form $('.post-thumb a').hover( -> $(this).find('.overlay').fadeIn(150) -> $(this).find('.overlay').fadeOut(150) ) – zw963 Dec 20 '16 at 02:06
25

For those searching for an answer in 2014 CoffeeScript,

$('someSelector').hover ->
  alert "hello"
, ->
  alert "world"

compiles into

$('someSelector').hover(function() {
  return alert("hello");
}, function() {
  return alert("world");
});
c0d3rman
  • 665
  • 6
  • 15