controllers as clean coffeescript classes

1,227 views
Skip to first unread message

xrd

unread,
Apr 20, 2012, 3:06:52 AM4/20/12
to ang...@googlegroups.com
When I first started learning about Angular I loved that coffeescript classes mapped right onto controllers like this:

(it does not work because I cannot figure out how to get jsfiddle, the coffee-script.js in-browser compiler, and angular to play nicely, but you get the point...)

Now with Angular 1.0 RC, I have to add all methods and models onto the scope, like so:


I think it is uglier than what I had before.  And, I was using extends with some of my classes (class FooCtrl extends Pagination) so I lose everything previously automatically added to my class and am not sure how I could refactor the base class in a clean way.

So, I thought, maybe I could define a method that imports all my methods onto the scope.  


I have not been able to figure it out how to implement extendByScope().  I was assuming I would need to iterate over the methods on the class and if it was a function, call apply with the $scope as "this" so that inside my method definition @clickCount used @/this as $scope.  Seems like a clever way to do it, but I have not been able to figure it out.

Comments or suggestions?

Chris 

Peter Bacon Darwin

unread,
Apr 20, 2012, 7:07:02 AM4/20/12
to ang...@googlegroups.com
Hi Chris,
I was using coffee script classes extensively but now I am inclined to use straight functions as controllers, writing direct to $scope instead of this (@) and use closure to keep everything together.  This gets rid of all those unsightly @ blemishes everywhere and also removes the need to use => binding on methods that will be called by angular. It also provide the ability to hide implementation, which is more clunky with coffeescript classes. An example:

# Angular will inject $scope and $location for us
module.controller 'MyController', [ '$scope', '$location', ($scope, $location)->
  somePrivateField = 'This is available throughout the controller but hidden from outside'

  $scope.fieldToUseInView = 'This field will be publicly visible in the scope'

  somePrivateMethod = (param1)->
    # do something with param1

  $scope.someHelperMethod = ()->
    # do something for the view, maybe use private methods and fields
    $scope.newField = somePrivateMethod(somePrivateField)
]

Personally, I find this syntax quite terse and agreeable.

If you want to inherit some functionality then you can call the super "class/function" in this function:

# Define super
MyBaseController = ($scope, $location)->
  # Do stuff with $scope, etc

module.controller 'MyController', [ '$scope', '$location', ($scope, $location)->
  # Call the base from here
  MyBaseController($scope, $location)

Because you are not relying on $scope for all you public stuff rather than this/@ then you don't have to worry about prototype chains.

I have also found that in many cases, where you feel you need a base controller, you can/should use a service instead or rely on the scope inheritance mechanism provided by angular.

My 2 pennies worth.

Pete

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To view this discussion on the web visit https://groups.google.com/d/msg/angular/-/IGgfbR3j5vQJ.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/angular?hl=en.

lucassus

unread,
Dec 6, 2012, 6:32:05 PM12/6/12
to ang...@googlegroups.com
Here is my simple solution: https://github.com/lucassus/mongo_browser/blob/16ef9f0e44ca4756d2de41f9e314e6cb3ffc9c00/app/assets/javascripts/app/controllers/databases.js.coffee

Basically you could treat methods defined on scopes as some kind of "public" methods which are available for templates.
Other methods ("private") could be defined as class methods.

Peter Bacon Darwin

unread,
Dec 7, 2012, 5:54:04 AM12/7/12
to ang...@googlegroups.com
For this to work when minified you would need to do :

module.controller "databases", ['$scope', 'Database', 'confirmationDialog', 'alerts', DatabasesController]



--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.

lucassus

unread,
Dec 7, 2012, 6:09:35 PM12/7/12
to ang...@googlegroups.com

Steve Watson

unread,
Dec 6, 2013, 5:29:56 AM12/6/13
to ang...@googlegroups.com
Just started to use CoffeeScript and I found this post really handy, thanks!

Martin Alix

unread,
Dec 6, 2013, 11:48:25 AM12/6/13
to ang...@googlegroups.com
You can declare a $inject property to avoid those ugly (imho) @$prop names, too.
Message has been deleted
Message has been deleted

Martin Alix

unread,
Dec 6, 2013, 11:54:41 AM12/6/13
to ang...@googlegroups.com
Chris, have you tried the "controller as" syntax with @prop = "whatever"?

http://docs.angularjs.org/api/ng.directive:ngController

Reply all
Reply to author
Forward
Message has been deleted
0 new messages