1

I am following a tutorial to get introduced AngularJS with Rails 4. At some point the author creates an Angular controller by doing this:

@restauranteur.controller 'HomeCtrl', ['$scope', ($scope) ->
  # Notice how this controller body is empty
]

I have read that @ means this in CoffeeScript, but I am confused on why do we need to define the controller with @. I have always read that in Angular you define controller like functions:

function MyCtrl( $scope ){

    $scope.someValue = "All your base are belong to us!";

}

The reference on the tutorial is this one: http://www.honeybadger.io/blog/2013/12/11/beginners-guide-to-angular-js-rails

mu is too short
  • 426,620
  • 70
  • 833
  • 800
StarTrek18
  • 323
  • 4
  • 15
  • The answer you accepted is absolutely wrong. And the guy who wrote the tutorial has no idea what he's doing with `@`. I'll post an answer below. – Esteban Apr 06 '14 at 16:35
  • Also, it's the module (`restauranteur`) that's being defined in the global namespace, not the controller. – Esteban Apr 06 '14 at 19:38

2 Answers2

2

It's a plain mistake by the tutorial author. @ in CoffeeScript always compiles to this in JavaScript, and followed by an identifier such as @restauranteur, it's this.restauranteur.

Inside a class or a function that will be bound to an object (we could call that a method), it makes a lot of sense since we're expecting the this object to have a restauranteur property. However, in the top scope of a file, which is how he uses it in your example, it makes no sense. It's also a very bad idea; let's see what this compiles to:

@restauranteur.controller 'HomeCtrl', ['$scope', ($scope) ->
  # Notice how this controller body is empty
]

As a .coffee file of its own, this gets us:

(function() {
  this.restauranteur.controller('HomeCtrl', ['$scope', function($scope) {}]);
}).call(this);

To be clear, that a function that's invocated as soon as it's defined is the module pattern (read more about it here).

Referencing this in a function that's not bound to a specific object will reference the global scope, window in the case of browsers. That means that you'll be able to do restauranteur from anywhere in your code, even in dependencies, other modules, etc. It's exactly the opposite that the module pattern looks for! It's completely unnecessary and you can remove it from everywhere that's not a class/method definition.

What the tutorial author is doing is also defining @restauranteur, thus window.restauranteur as a module in a different file (main.js.coffee):

@restauranteur = angular.module('restauranteur', [])

That's the only reason it works. However, he should've done it this way to not pollute the global namespace:

main.js.coffee

restauranteur = angular.module('restauranteur', [])

restauranteur.config(['$routeProvider', ($routeProvider) ->
  [...]

Actually, the definition of restauranteur as a variable is useless since he uses its value only once in the file. It might help readability, though.

HomeCtrl.js.coffee

angular.module('restauranteur').controller 'HomeCtrl', ['$scope', ($scope) ->
  # Notice how this controller body is empty
]

By contrast, using @ is useful here:

describe Restaurant do
  before do
    @restaurant = Restaurant.new(name: "Momofuku")
  end
[...]

Here, restaurant will be part of the this object that's accessible from every test, so you can use it like this:

describe "when name is not present" do
  before { @restaurant.name = " " }
  it { should_not be_valid }
end

because this is the same in both cases, and not just because it's the global scope. Let's see a simpler example:

class Restaurant
  isOpen = false

  open: ->
    @isOpen = yes

  close: ->
    @isOpen = no

In this case, isOpen will be an instance field of Restaurant instances, since this will be the instance for which the method was called, for example like this:

myRestaurant = new Restaurant
myRestaurant.open()

I hope that was clear enough. I suggest you read through the CoffeeScript homepage from top to bottom, it's pretty short and straightforward. Also, please be sure to have a good JavaScript background before attempting to use CoffeeScript for real projects, it will save you a couple of headaches.

Community
  • 1
  • 1
Esteban
  • 2,540
  • 21
  • 27
  • the assignment is on the module the tutorial author created, it's not in the global namespace. instead of compiling as shown, it would compile to: `angular.module('restauranteur',[]).controller('HomeCtrl'.....`). I'm not an expert of coffeescript, but it seems this is the shorthand assignment operator of a static property on an object, in this case the specific module, and not `window`. – Brian Vanderbusch Apr 06 '14 at 18:27
  • No, you're wrong, please stop misleading people here... it won't compile to that, where do you take that from? It's nonsense! This is **not** assignment of a static property, that sentence doesn't even have a meaning in JavaScript, please stop opining! – Esteban Apr 06 '14 at 19:18
  • Also, I have taken the **CoffeeScript compiler** to produce that output, not my imagination. Unless the OP is using some magical AngularJS-coupled CoffeeScript compiler, he's never going to get `angular.module('restauranteur', [])` from `@restauranteur`!! I'll extend my answer to show you how it works. – Esteban Apr 06 '14 at 19:24
  • Also, using `angular.module('restauranteur', [])` to create a controller would've overwritten the previously created module, since passing a module dependency array as second parameter will create a module instead of retrieving it. – Esteban Apr 06 '14 at 19:33
  • My answer wasn't *absolutely* wrong, just the edited part. However your answer covers the concerns my initial answer did and you are clearly more experienced with coffeescript. See my edited answer. – Brian Vanderbusch Apr 06 '14 at 22:11
0

Please review and accept esteban's answer instead. His answer covers the components about mine that were correct, and has more appropriate information about cofeescript vs javascript

Brian Vanderbusch
  • 3,313
  • 5
  • 31
  • 43
  • Thanks for the answer. Still, Why the @ in front of restaurant? What does that mean? – StarTrek18 Apr 05 '14 at 07:12
  • Interesting. I thought in coffeescript you declared variables just by doing ``myvar = 'myvalue'``. – StarTrek18 Apr 05 '14 at 07:31
  • @StarTrek18 please review my answer and, once you've understood why it's correct and this one isn't, accept it. I'm willing to go out of my way to prevent this BS from being accepted. Also, comprehensions have nothing to do with this, there's not even one used thoughout the tutorial. – Esteban Apr 06 '14 at 19:34