Gio Polvara
Gio Polvara

Reputation: 26988

Use CoffeeScript's class in AngularJS directive controller

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.

Upvotes: 2

Views: 2018

Answers (3)

Brian Sullivan
Brian Sullivan

Reputation: 31

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.

Upvotes: 0

Gio Polvara
Gio Polvara

Reputation: 26988

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

Upvotes: 0

Martin K
Martin K

Reputation: 782

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)

Upvotes: 5

Related Questions