2

While creating AngularJS directives with CoffeeScript I was using this approach:

angular
.module('MyApp', [])
.directive 'myDirective', ->
restrict: 'E'
controllerAs: 'ctrl'
controller: ->
  new class
    constructor: ->
      @value = 3

This code works with Angular 1.2.14—jsbin—but does not with 1.3.0—jsbin. I don't have any error in the console, simply it does nothing. It appears that the controller is an empty object.

Gio Polvara
  • 23,416
  • 10
  • 66
  • 62
  • This works pretty well for me: http://stackoverflow.com/questions/27172394/javascript-doest-convert-angular-ui-datepicker-date-to-utc-correctly/29030439#29030439 – frhd Mar 13 '15 at 22:32

3 Answers3

5

I answered almost the same question in this thread: AngularJS + Coffeescript - 'Hello World' directive not working. I like keeping my Angular objects as proper CoffeeScript classes. The key is to wrap the new Directive() inside a function block.

class MyDirective
    constructor: (myService) ->
        // Constructor stuff
        @controller = MyController
        @controllerAs = 'ctrl'
    restrict: 'E'
    replace: true
    scope:
        attributeStuff: '='
    link: (scope, element, attr) ->

angular.module('my_module').directive 'MyDirective', (myService) ->
    new MyDirective(myService)
Community
  • 1
  • 1
Martin K
  • 782
  • 7
  • 13
  • With your method it seems not possible to use the `controllerAs` syntax. – Gio Polvara Oct 29 '14 at 10:18
  • I see, but still I don't understand the advantage of doing that. – Gio Polvara Nov 11 '14 at 14:14
  • 3
    Well I like to either have everything in classes or everything in Angular modules, not a mixture of both. And since I prefer to write Controllers and Services as classes I want the same for Directives. Consistency is king – Martin K Nov 14 '14 at 08:01
0

I did some further research: it seems that in Angualar 1.3.0 if you use controllerAs Angular will take controller and execute new on it. So this code fixes the problem:

angular
.module('MyApp', [])
.directive 'myDirective', ->
restrict: 'E'
controllerAs: 'ctrl'
controller: class
  constructor: ->
    @value = 3
Gio Polvara
  • 23,416
  • 10
  • 66
  • 62
0

I use a pattern for defining my controllers with coffeescript classes and attaching them to the directive (also defined in coffeescript) with controllerAs so I can access the class properties and methods in the template. I also defined the classes using the controller provider. This worked great in angular 1.2.15 but broke when I updated to 1.3.6.

After much debugging, I realized that angular was no longer automatically putting the object instance returned by the coffeescript class onto the scope. The fix is very simple: manually put the instantiated class object on the scope, as show below:

myModule.directive 'cePageHeader',  ->
  restrict: 'A'
  templateUrl: 'shared/ce-page-header.tpl.html'
  replace: true
  scope: true
  controller: 'CePageHeaderDirectiveCtrl as cePageHeaderDirCtrl'

cePageHeaderDirectiveModule.controller 'CePageHeaderDirectiveCtrl',
(UserModel, $scope) ->
  $scope.cePageHeaderDirCtrl =
  new class CePageHeaderDirectiveCtrl
    constructor: ->
      @user = UserModel

    goHome: ->
      console.log "Do something to go home"

Previously, the function simply returned the object created by the class. Adding this one line fixed the problem with 1.3.6:

$scope.cePageHeaderDirCtrl =

BTW, in the template I can access my class object like this:

<a class="navbar-brand" ng-click="cePageHeaderDirCtrl.goHome()">
  Go Home

Without the manually assignment to the $scope, $scope.cePageHeaderDirCtrl = {}, an empty object.